`
nigel521
  • 浏览: 11399 次
社区版块
存档分类
最新评论

黑马程序员——File类与特殊流

 
阅读更多

------- android培训java培训、期待与您交流! ----------

File类
概述:用来将文件或者文件夹封装成对象。方便对文件与文件夹进行操作。File对象可以作为参数传递给流的构造函数。弥补了流的很多不足,流只能操作数据,不能操作文件的属性信息。如果需要对文件属性信息进行操作,需要用File。
/*File类的常见方法:
 * 1.创建:
 * (1).创建文件:boolean createNewFile()此方法用于通过file对象在硬盘上创建文件。其实底层是应用了输出流的特点。
 * 如果该文件已经存在,创建失败返回false,否则创建成功返回true。
 * (2).创建文件夹(路径):mkdir(),创建一级目录。mkdirs()创建多级目录。
 *
 * 2.删除:boolean delete()与boolean deleteOnExit的区别:在创建完成一个file对象后,往往会对它进行操作,
 * 在操作过程中难免会遇到一些问题(例如抛异常),使得delete()方法执行不到,文件删除不了。浪费了系统资源,
 * 而deleteOnExit方法就是来解决这一问题的。
 *
 * 3.判断
 * File f = new File("1.txt");
 * 不一定是文件,因为如果调用f.mkdir();就是文件夹。不要想当然地认为。
 * (1),exists():判断文件是否存在,在硬盘上是否存在。
 * (2),isFile():判断是否为文件。先判断文件是否存在exsists()
 * (3),isDirectory():判断文件是否是文件夹。先判断文件是否存在exsists()
 * (4),isHidden();如果是隐藏文件不予与处理。
 * (5),isAbsolute();判断是否是绝对路径,只判断路径,与文件存不存在没有关系。
 *
 * 4.获取信息
 * 在涉及到对路径操作的方法时候,即使该文件不存在,也可以进行正常操作。
 * (1),getName()返回由此抽象路径名表示的文件或目录的名称。
 * (2),getPath()将此抽象路径名转换为一个路径名字符串。
 * (3),getParent() 返回此抽象路径名父目录的路径名字符串;如果此路径名没有指定父目录,则返回 null。
 * (4),getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。
 * (5),lastModified()返回此抽象路径名表示的文件最后一次被修改的时间。
 * (6),length()  返回由此抽象路径名表示的文件的长度。
 *
 * 5.其他方法:
 * (1),list();目录下的所有文件的名字。用list方法的file对象必须是一封装了一个目录。该目录还必须存在。
 * (2),listRoots();获取盘符。
   (3),static File[] listRoots():获取的是被系统中有效的盘符。
   (4),String[] list():获取指定目录下当前的文件以及文件夹名称。
   (5),String[] list(Filenamefilter):可以根据指定的过滤器,过滤后的文件夹名称。
   (6),File[] listFile():获取指定目录下的文件以及文件夹对象。
   (7),renameTo(File):
 File f1 = new File(“C:\\a.txt”);
File f2 = new File(“C:\\b.txt”);
f1.ranameTo(f2);//将c盘下的a.txt文件改名为b.txt文件。
 
list(new FilenameFilter())代码示例:

File dir = new File("d:\\heimaio\\");
  String[] arr = dir.list(new FilenameFilter() {
   // 文件名过滤器,文件过滤接口。提供了accept方法,如果返回false,表示不接受,过滤全部。当返回true时候,不过滤
   // 通过list方法获取文件的名字,如果有不想要的文件名字,需要过滤那么就使用这种方法。   

   public boolean accept(File dir, String name) {
    if (!name.endsWith(".mp3"))
     return false;
    return true;
 //return name.endsWith(“.mp3”);

   }

  });
  for (String name : arr) {
   System.out.println(name);
  }
  System.out.println(arr.length);
  */ 

 


递归

package io;

import java.io.File;

public class FileDemo3 {
 /*
  * 递归要注意: 一般用递归能实现的,用循环也能实现。 1.限定条件 2.要注意递归的次数,尽量避免内存溢出
  */
 public static void main(String[] args) {
//  method1(new File("d:\\java征程\\java视频\\毕向东"));
  System.out.println(method2(4));
//  删除文件夹,删除的原理:1.从里往外删,遍历每一个文件。然后删除2.利用递归,给定限定条件:如果遍历的
//  是文件就删除。
  removeDir(new File("d:\\heimaio\\file.txt"));
  
 }

 private static void removeDir(File dir) {
  File[] files = dir.listFiles();
  for(File f: files){
   if(f.isDirectory())
    removeDir(f);
   else{
    System.out.println(f+"::"+f.delete());
   }
  }
  System.out.println(dir+":"+dir.delete());
 }
 // 利用递归算出连续整数的乘积。

 private static int method2(int i) {
  if(i==1)
//   限定条件。
   return 1;
  return method2(i-1)*i;
   
 }

 // 利用递归方法便利出是文件指定目录下的文件。
 private static void method1(File dir) {
  File[] f = dir.listFiles();
  for (File f1 : f) {
   // 限定条件
   if (f1.isDirectory())
    method1(f1);
   else {
    System.out.println(f1);
   }
  }
 }
 

}

Properties对象。

/*Properties是hashtable的子类。
也就是说它具备map集合的特点。而且它里面存储的键值对都是字符串。
是集合中和IO技术相结合的集合容器。

该对象的特点:可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有固定格式:键=值。
*/
public class PropertiesDemo
{
 public static void main(String[] args) throws IOException
 {
  //method_1();
  loadDemo();
 }

 public static void loadDemo()throws IOException
 {
  Properties prop = new Properties();
  FileInputStream fis = new FileInputStream("info.txt");
  //将流中的数据加载进集合。
  prop.load(fis);
  prop.setProperty("wangwu","39");
  FileOutputStream fos = new FileOutputStream("info.txt");

  prop.store(fos,"haha");

 // System.out.println(prop);
  prop.list(System.out);

  fos.close();
  fis.close();

 }
 //演示,如何将流中的数据存储到集合中。
 //想要将info.txt中键值数据存到集合中进行操作。
 /*
  1,用一个流和info.txt文件关联。
  2,读取一行数据,将该行数据用"="进行切割。
  3,等号左边作为键,右边作为值。存入到Properties集合中即可。

 */
PrintWriter和PrintStream

/*
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。

字节打印流:
PrintStream
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream


字符打印流:
PrintWriter
构造函数可以接收的参数类型:
1,file对象。File
2,字符串路径。String
3,字节输出流。OutputStream
4,字符输出流,Writer。
*/
5.SequenceInputStream合并流对象
package io;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.util.Enumeration;
import java.util.Vector;
public class SequenceInputStreamDemo {
 // SequenceInputStream 表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,
 // 接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。
 // 此流用来解决:如果几个源想往一个目的上面写数据,用以前的方法,就是对文件进行续写。而用SequenceInputStream流可以把几个
 // 源文件合并在一起。达成一个源到一个目的的目的。代码示例:
 public static void main(String[] args) throws IOException {
  // 将三个读取流放在一个集合中
  Vector<InputStream> v = new Vector<InputStream>();
  v.add(new FileInputStream("d:\\heimaio\\filedemo.txt"));
  v.add(new FileInputStream("d:\\heimaio\\filedemo2.txt"));
  v.add(new FileInputStream("d:\\heimaio\\filedemo3.txt"));
  Enumeration<InputStream> en = v.elements();
  // 转换成枚举,作为参数传SequenceInputStream这样就合并成了一个流。
  SequenceInputStream sis = new SequenceInputStream(en);
  BufferedWriter bw = new BufferedWriter(new FileWriter(new File(
    "d:\\heimaio\\together.txt")));
  byte[] buf = new byte[1024];
  int len = 0;
  while ((len = sis.read(buf)) != -1) {
   String str = new String(buf, 0, len);
   bw.write(str);
   bw.newLine();
   bw.flush();
  }
  
  sis.close();
  bw.close();
 }

}
切割文件。

 /*
  * public static void splitFile()throws IOException {
  * 关联被切的文件。
  * FileInputStream fis =
  * new FileInputStream("c:\\1.bmp");
  * FileOutputStream fos = null;
  * byte[] buf = new byte[1024*1024];
  * int len = 0; int count = 1; while((len=fis.read(buf))!=-1) { fos = new
  * 每次缓冲区读满的时候,都会写出不同名字的文件碎片
  * FileOutputStream("c:\\splitfiles\\"+(count++)+".part");
  * fos.write(buf,0,len); fos.close(); }
  *
  * fis.close();
  * }
  *切完以后,可以使用SequenceInputStream合并流把它还原。
  */


操作对象ObjectInputStream与ObjectOutputStream.
package io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class ObjectOutputStreamDemo {
 // 对象的序列化:可对对象进行持久化的存储。如果你想把一个对象通过流的方式写到指定的目的中,那么该对象必须进行序列化,所谓序列化就是给对象标记下(Uid是根据类中的成员进行标示的,把类进行唯一标示)。如果之前把一个对象存入到了硬盘中,在后来读取时候(该类文件成员被修改),那么此类的默认uid也会改变。读取过程中会抛出java.io.InvalidClassException异常,如果之前你已经生成了UID号,没有使用默认的。那么就不会报出此异常。(文件中对象序列号必须和class文件中的序列号是一样的)。
注意:static不能被序列化,如果非静态的不想被序列化,那么就transient(关键字) String name=”gekui”.
 // 才能完成写对象的操作。写对象用的方法是ObjectOutputStream.
 public static void main(String[] args) throws IOException {
//将要操作的文件封装在一个file对象里面,判断有无,是否要创建。
  File file = new File("d:\\heimaio\\ObjectOutputStreamDemo.txt");
  if(!file.exists()){
   file.createNewFile();
  }
//  通过ObjectOutputStream对象,将指定的对象写入到File文件中去。
  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
  oos.writeObject(new Person("gekui",21));
  oos.close();
 }
}

管道流

package io;

import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;

/*
 * PipedInputStream和PipedOutputStream,在以往的输入输出流对数据操作,通常需要一个中转站(数组)对数
 * 据进行缓存。输出流再把缓存中的数据写入到目的中。在执行一些特点操作的时候,这是很麻烦的。出现了一个
 * 管道流,不需要任何中转,输入输出流可以像管道一样对接在一块。
 *
 * 管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。通常,数据由某个线程从
 *  PipedInputStream 对象读取,并由其他线程将其写入到相应的 PipedOutputStream。不建议对这两个对象尝试
 *  使用单个线程,因为这样可能死锁线程。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作
 *  分离开。如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。
 */
示例代码:
public class PipedDemo {
 public static void main(String[] args) throws IOException {

  PipedInputStream in = new PipedInputStream();
  PipedOutputStream out = new PipedOutputStream();
  out.connect(in);

  Read r = new Read(in);
  Write w = new Write(out);
  new Thread(r).start();
  new Thread(w).start();

 }
}

class Read implements Runnable {
 private PipedInputStream in;

 Read(PipedInputStream in) {
  this.in = in;
 }

 public void run() {
  try {
   byte[] buf = new byte[1024];

   System.out.println("读取前。。没有数据阻塞");
   int len = in.read(buf);
   System.out.println("读到数据。。阻塞结束");

   String s = new String(buf, 0, len);

   System.out.println(s);

   in.close();

  } catch (IOException e) {
   throw new RuntimeException("管道读取流失败");
  }
 }
}

class Write implements Runnable {
 private PipedOutputStream out;

 Write(PipedOutputStream out) {
  this.out = out;
 }

 public void run() {
  try {
   System.out.println("开始写入数据,等待6秒后。");
   Thread.sleep(6000);
   out.write("piped lai la".getBytes());
   out.close();
  } catch (Exception e) {
   throw new RuntimeException("管道输出流失败");
  }
 }
}
8. RandomAccessFile一个特殊的读写类

package io;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
/*

该类不是算是IO体系中子类。
而是直接继承自Object。

但是它是IO包中成员。因为它具备读和写功能。
内部封装了一个数组,而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置,
同时可以通过seek改变指针的位置。


其实完成读写的原理就是内部封装了字节输入流和输出流。

通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,,读写rw等。

如果模式为只读 r。不会创建文件。会去读取一个已存在文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存则不会覆盖。

*/
public class RandomAccessFileDemo {
 public static void main(String[] args) throws Exception {
//   writeFile();
   writeFile_2();
  readFile();
 }

 
 private static void readFile() throws IOException {
  File file = new File("d:\\heimaio\\random.txt");
  if(!file.exists()){
   file.createNewFile();
  }
  RandomAccessFile raf = new RandomAccessFile(file,"r");
//  可以随意的修改指针的位置
  raf.seek(30);
//  只能往后面跳,不能往前面跳
  raf.skipBytes(10);
//  查看指针的位置
  System.out.println(raf.getFilePointer());
  byte[] buf = new byte[4];
  raf.read(buf);
  String str = new String(buf);
  System.out.println(str);
 }

 private static void writeFile_2() throws Exception {
  File file = new File("d:\\heimaio\\random.txt");
  if (!file.exists()) {
   file.createNewFile();
  }
  RandomAccessFile raf = new RandomAccessFile(file, "rw");
  // 指定指针的位置。
  raf.seek(8 * 5);
  raf.write("1234".getBytes());
  raf.close();
 }

 private static void writeFile() throws Exception {
  File file = new File("d:\\heimaio\\random.txt");
  if (!file.exists()) {
   file.createNewFile();
  }

  RandomAccessFile raf = new RandomAccessFile(file, "rw");
  raf.write("葛奎".getBytes());
  raf.writeInt(97);
  raf.write("王帆".getBytes());
  raf.writeInt(98);
  raf.close();
 }
}

9.操作基本数据类型的流对象DataStream
主要用来操作基本类型数据,提供了各种操作基本类型的数据的方法。还有一个writeUTF()方法。该方法写入的字符是占4个字节的,所以它只能用其自己的方法读取readUTF();
10.操作字节数据的对象
 /*
  * 特点:不与流底层打交道,所以不涉及流的底层操作。
  * ByteArrayInputStream:在构造的时候,需要接受数据源。。而且数据源是一个字节数组。
  * ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了 可变长度的字节数组。这就是数据目的地。
  * 因为这两个流对象都操作的数组,并没有使用系统资源。所以,不用进行close关闭。
  *
  * 用流的读写思想来操作数组。
  *
  * 源设备, 键盘 System.in,硬盘 FileStream,内存 ArrayStream。 目的设备: 控制台
  * System.out,硬盘FileStream,内存 ArrayStream。
 
  * 用流的读写思想来操作数据。
  *
  * 以下两种对象的思想和ByteStream是一样的。
  * 操作字符的数组CharArrayReader和CharArrayWrite 操作字符串StringReader和StringWriter
  */


 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics