IO知识点汇总1
1、File类
一般使用我们可能是像这样
File inFile = new File("*****");
File outFile = new File("*****");
new一个File然后用输入流读文件。
InputStream in = new FileInputStream(inFile);
文件如果不存在,会报FileNotFound
File提供isFile()方法验证目录正确文件存在,可以来做验证
InputStream in = null; if (inFile.isFile()) { in = new FileInputStream(inFile); }
写文件的时候
OutputStream out = new FileOutputStream(outFile);
这种情况文件如果不存在,会自动创建。
但需要注意的是,如果路径不存在,会FileNotFound,而不会自动创建路径的
File提供了mkdir()和mkdirs()方法来创建目录
File parrent = outFile.getParentFile(); if (!parrent.exists()) { parrent.mkdirs(); } OutputStream out = new FileOutputStream(outFile);
mkdirs和mkdir不同的是mkdirs可以创建多级目录而mkdir只能创建单层目录,其实mkdirs实现就是递归一层一层做mkdir。
File还提供很多方法,比如创建文件createNewFile,获取据对路径getAbsolutePath,获取磁盘空间等等,都比较简单需要的时候直接使用即可。
2、InputStream
InputStream提供了三种读的方法
read()方法,读一个字节,返回这个字节的int值
byte[] bytes = new byte[1024]; int i = 0; while (true) { int j = in.read(); if (j == -1) { break; } bytes[i++] = (byte) j; } System.out.println(new String(bytes, 0, i));
大概可以这样使用把,不严谨因为我知道文件就几个字节。大文件需要外面再套一层循环,whiletrue换成有条件的循环,可以参考下面的read(byte[],int,int)
read(byte[])方法其实是read(byte[],0,byte.leng),所以主要看read(byte[],int,int)源码
可以看到,类似上面写的逻辑,也是使用read()来一个字节一个字节读,把读到的字节放到byte[]中。
返回的并不是读到的数据,而是字节数,-1表示读完了。数据放在byte[]里。
我们平常使用比较多的应该是read(byte[])方法
byte[] bytes = new byte[1024]; int i; StringBuilder builder = new StringBuilder(); while ((i = in.read(bytes)) != -1) { builder.append(new String(bytes, 0, i)); } System.out.println(builder.toString());
使用完后记得close(),也可以使用apache的common包的一些方法来close。
InputStream还提供skip(long)方法跳过字节,reset和mark可以重复利用流,不过inputstream默认不支持。
3、OutputStream
OutputStream提供的方法很简单,3个write方法,flush,close
类似InputStream,不做详细介绍了。不同的是读的时候可能经常使用read(byte[]),而写的时候一般使用write(byte[],int,int),如下:
byte[] bytes = new byte[1024]; int i; while ((i = in.read(bytes)) != -1) { out.write(bytes, 0, i); }
这个write的时候还是要注意的,可能bytes里有效数据不满,如果直接使用write(byte[])会出问题的。
flush方法有必要说下,输出流输出的时候一般是先写在缓冲区中,然后再写入文件中。当完成输出流的输出后,可能缓冲区还没满,可能就不写入文件,所以这会儿需要flush强制将缓冲区的内容写入文件中。所以一般输出流在close之前需要先flush。
4、FileInputStream和FileOutputStream
前面举的例子基本使用FileInputStream和FileOutputStream。一些特有的方法后面使用过程中遇到再做总结。
5、FilterInputStream和FilterOutputStream
FilterInputStream是InputStream特殊的子类,里面包含了一个InputStream
通过构造方法传入这个InputStream
FilterInputStream子类,对InputStream进行改装,在原有的InputStream基础上提供了新的功能。
DataInputStream,可以直接从stream中读取基本类型、字符串等类型数据
DataOutputStream out = new DataOutputStream(new FileOutputStream("***")); out.writeInt(112314); out.writeUTF("hello world"); out.writeBoolean(true); out.flush(); out.close(); DataInputStream in = new DataInputStream(new FileInputStream("*")); int i = in.readInt(); System.out.println(i); String s = in.readUTF(); System.out.println(s); boolean b = in.readBoolean(); System.out.println(b); in.close();
DataInputStream暂时没有想到一些合适的使用场景,以后碰到了再研究了解下。
BufferedInputStream和BufferedOutputStream。
使用方法参考前面列的InputStream,区别是BufferedInputStream和BufferedOutputStream提供了一个字节数组当缓存。每次read的时候先看缓存有没有,没有再从InputStream中读。输出时也是先写到缓存数组中,满了活着flush,一次性写OutputStream中。
FilterInputStream和FilterOutputStream是装饰者模式的一个比较典型的应用。
6、ObjectInputStream和ObjectOutputStream
可以直接对类进行读写
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/Users/lianzhehua/workSpace/testMain/src/main/resources/test.txt")); out.writeObject(new Person("a", 22)); out.writeObject(new Person("b", 23)); out.writeObject(new Person("c", 24)); ObjectInputStream in = new ObjectInputStream(new FileInputStream("/Users/lianzhehua/workSpace/testMain/src/main/resources/test.txt")); try { while (true) { Object obj = in.readObject(); Person a = (Person) obj; System.out.println(a); } } catch (EOFException e) { }
这里提一下transient关键字,修饰的变量不参与序列化,可能有些同学不太了解。
ObjectInputStream还提供对基本数据类型和字符串的读写,类似DataInputStream