在梳理IO流相关的知识点,我感觉主要分为以下几个部分:
IO流是实现输入输出的基础,在Java中将不同的输入输出源描述为“流”。流的分类:
输入流:从外向内。(即将数据读取到内存中)
输出流:从内向外
Java的输入流主要是:InputStream 、Reader
Java的输出流主要是:OutputStream、Writer
它们都是一些抽象基类,无法直接创建实例。
字节流和字符流的用法几乎一样,区别在于字节流和字符流操作的数据单元不一样,(InputStream / OutputStream)字节流操作数据单元是8位的字节,(Reader/Writer)而字符流操作的是16位的字符。
在InputStream和Reader中主要包含3个方法:
int read() 从输入流中读取单个字符,返回所读取的字节数据(字节数据可以直接转换位int类型)
int read(byte[] b) 从输入流中最多读取 b.length 个字节的数据,并将其放到字节数组b中,返回实际读取的字数,如果没有读取到则返回-1。
int read(byte[] b,int off ,int len)其中,off是偏移量,len是读取的长度,并将其读取到字节数组中。
具体操作:
package IOTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/*
*
* 测试FileOutputStram FileInputStram
* 测试FileWriter FileReader
* */
public class Test1 {
// 使用 FileOutputStream将数据写入到本地文件
public static void FileOutputStreamTest() {
String str = "helloWord!";
try {
FileOutputStream fos = new FileOutputStream(new File("C:\\Users\\Microtao\\Desktop\\helloWord.txt"));
byte[] ch = new byte[1024];
ch = str.getBytes();
fos.write(ch);
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 使用 FileInputStream 读取本地文件
public static void FileInputStreamTest() {
// 读取文件
try {
FileInputStream fis = new FileInputStream(new File("C:\\Users\\Microtao\\Desktop\\helloWord.txt"));
byte[] ch = new byte[1024];
int length = 0;
while ((length = fis.read(ch)) != -1) {
System.out.println(new String(ch, 0, length));
}
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
// 使用FileWriter 将数据写入到本地磁盘
public static void FileWriterTest() {
try {
FileWriter fw = new FileWriter(new File("C:\\Users\\Microtao\\Desktop\\helloWord2.txt"));
fw.write(new String("这是第二个"));
fw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
// 使用FileReader 读取本地文件
public static void FileReaderTest() {
String pathname = "C:\\Users\\Microtao\\Desktop\\helloWord.txt";
try {
FileReader fr = new FileReader(new File("C:\\Users\\Microtao\\Desktop\\helloWord2.txt"));
char[] ch = new char[1024];
int length = 0;
while ((length = fr.read(ch)) != -1) {
System.out.println(new String(ch, 0, length));
}
fr.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// 使用 FileOutputStream将数据写入到本地文件
FileOutputStreamTest();
// 使用 FileInputStream 读取本地文件
FileInputStreamTest();
// 使用FileWriter 将数据写入到本地磁盘
FileWriterTest();
// 使用FileReader 读取本地文件
FileReaderTest();
}
}
处理流可以隐藏底层设备上节点流的差异,并对外提供更加方便的输入/输出方法,让程序员更加关心高级流的操作。使用处理流的典型思路:使用处理流来包装节点流,程序通过处理流来执行输入/输出功能, 实际识别处理流非常简单,只要流的构造器参数不是一个物理节点,而是已经存在的流,那么这种流一定是处理流;而所有的节点流都是直接以物理IO节点作为构造器参数的。
例如使用PrintStream处理流来包装OutputStream:
public static void PrintStreamTest() {
try {
FileOutputStream fos = new FileOutputStream("C:\\Users\\Microtao\\Desktop\\baozhuangliu.txt");
PrintStream ps = new PrintStream(fos);
ps.println("包装流输出的!");
ps.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
由于PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。在处理流包装了底层节点流之后,关闭输入/输出流时,只用关闭最上层的处理流即可,系统会自动关闭被包装流包装的节点流。
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
通常有一个规则:如果进行输入/输出操作的内容是文本内容,则应该考虑使用字符流;如果是二进制内容,考虑使用字节流。
Java只提供了将字节流转换成字符流,而没有将字符流转换成字节。为什么?
因为:字节流比字符流使用更广泛,但字符比字节操作更方便,为什么要将字符转换成字节呢?反之,现在有一个字节流,而且直到它是文本内容,所以将其转换成字符流(char)使用起来更加方便。
【参考文章】https://www.cnblogs.com/QQ846300233/p/6046388.html