1、流的分类
主要分类方法:
按操作数据单位不同分为:字节流(8 bit,处理非文本文件),字符流(16 bit,处理文本文件)
按作用方式不同:节点流(直接作用在文件上),处理流(作用在已有流上的)
这里我们主要介绍常用的字节流和字符流。
抽象基类 | 字节流 | 字符流 |
---|---|---|
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
其他不同的流均实现了以上四种基类,名称上也是以基类名字结尾。
需要注意当使用File类读取文件时,在main()方法中的相对路径是基于当前工程的;在单元测试中的相对路径是相较于当前module的!!!
2、四个访问文件的文件流(属于节点流)
抽象基类 | 文件流(节点流) |
---|---|
InputStream | FileInputStream |
OutputStream | FileOutputStream |
Reader | FileReader |
Writer | FileWriter |
四个节点流实现了抽象基类,属于直接操作文件。
1)FileReader
FileReader fileReader = null; // 单独列出是因为在finally中仍需要使用fileReader。
try {
File file = new File("hello.txt");
fileReader = new FileReader(file);
int data = fileReader.read();
while (data != -1) {
System.out.print((char) data);
data = fileReader.read();
}
/* 一次读取多个字符
char[] cbuf = new char[5];
int len;
while ((len = fileReader.read(cbuf)) != -1) {
for (int i = 0; i < len; i++) {
System.out.print(cbuf[i]);
}
}
*/
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileReader != null)
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
注意,在调用FileReader的构造器和使用read()函数时,会抛出异常。read()函数返回的时一个int型数值,和我们想要获得的字符不一致,所以需要转成char类型的。如果read()达到文件末尾会返回-1。
2)FileWriter
FileWriter fileWriter = null;
try {
File file = new File("hello1.txt");
fileWriter = new FileWriter(file);
// fileWriter = new FileWriter(file, true); // 在文件上追加内容
fileWriter.write("i am a person");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileWriter != null)
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
调用FileWriter时,如果文件不存在,会自动创建文件。其他与FileReader类似。可以将以上两者合并起来使用。
注意字符流不能处理图片!!!
3)FileInputStream && FileOutputStream
FileInputStream && FileOutputStream是用来操作字节流的,具体步骤和FileReader && FileWriter 类似,只在缓存部分有区别即:操作字节流用byte[],操作字符流用char[]。
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcFile = new File("屏幕截图.png");
File destFile = new File("屏幕截图-副本.png");
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
byte[] buffer = new byte[5];
int len;
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、四个缓冲流(属于处理流)
抽象基类 | 文件流(节点流) | 缓冲流(处理流) |
---|---|---|
InputStream | FileInputStream | BufferedInputStream |
OutputStream | FileOutputStream | BufferedOutputStream |
Reader | FileReader | BufferedReader |
Writer | FileWriter | BufferedWriter |
缓冲流是对文件流的包装,目的是提高文件处理效率。
使用缓冲流(字节型)来实现一个非文本文件的复制,和上文相比只是多了一个BufferedInputStream,需注意在关闭BufferedInputStream时,FileInputStream 也会自动关闭。
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
File srcFile = new File("屏幕截图.png");
File destFile = new File("屏幕截图-副本.png");
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(destFile);
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
byte[] buffer = new byte[5];
int len;
while ( (len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用字符型缓冲流同理