-
BufferedInputStream
-
LineNumberInputStream
-
ObjectInputStream
-
PipedInputStream
-
SequenceInputStream
-
StringBufferInputStream
这么多子类不需要每一个都记住,只需要记住两个:
FileInputStream
FileInputStream
是文件字节输入流,就是对文件数据以字节的方式来处理,如音乐、视频、图片等。
BufferedInputStream
使用方式基本和FileInputStream
一致。
BufferedInputStream
有一个内部缓冲区数组,一次性读取较多的字节缓存起来,默认读取defaultBufferSize = 8192
,作用于读文件时可以提高性能。
2.2、OutputStream——字节输出流
OutputStream
是相对 InputStream
的,既然有输入就有输出。OutputStream
这个抽象类是表示以上输出字节流的所有类的超类(父类)。
OutputStream
中的三个基本的写方法:
-
abstract void write(int b):往输出流中写入一个字节。
-
void write(byte[] b) :往输出流中写入数组b中的所有字节。
-
void write(byte[] b, int off, int len) :往输出流中写入数组 b 中从偏移量 off 开始的 len 个字节的数据。
其它重要方法:
-
void flush() :刷新输出流,强制缓冲区中的输出字节被写出。
-
void close() :关闭输出流,释放和这个流相关的系统资源。
OutputStream
的子类有:
-
ByteArrayOutputStream
-
FileOutputStream
-
FilterOutputStream
-
BufferedOutputStream
-
DataOutputStream
-
PrintStream
-
ObjectOutputStream
-
PipedOutputStream
StringBufferInputStream 和 StringBufferInputStream 已经过时了,这里不介绍了
FileOutputStream、BufferedOutputStream 和 FileInputStream、BufferedInputStream 是相对的。
2.3、Reader——字符输入流
Reader
是所有的输入字符流的父类,它是一个抽象类。
常见的子类有:
-
BufferedReader
-
LineNumberReader
-
CharArrayReader
-
FilterReader
-
PushbackReader
-
InputStreamReader
-
FileReader
-
PipedReader
-
StringReader
总结:
-
BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它 Reader 对象。
-
InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。
Reader 基本的三个读方法(和字节流对应):
(1) public int read() throws IOException; 读取一个字符,返回值为读取的字符。
(2) public int read(char cbuf[]) throws IOException; 读取一系列字符到数组 cbuf[]中,返回值为实际读取的字符的数量。
(3) public abstract int read(char cbuf[],int off,int len) throws IOException; 读取 len 个字符,从数组 cbuf[] 的下标 off 处开始存放,返回值为实际读取的字符数量,该方法必须由子类实现。
2.4、Writer——字符输出流
Writer 是所有的输出字符流的父类,它是一个抽象类。
常见的子类有:
-
BufferedWriter
-
CharArrayWriter
-
FilterWriter
-
OutputStreamWriter
-
FileWriter
-
PipedWriter
-
PrintWriter
-
StringWriter
总结:
-
OutputStreamWriter 是 OutputStream 到 Writer 转换的桥梁,它的子类 FileWriter 其实就是一个实现此功能的具体类。
-
BufferedWriter 是一个装饰器为 Writer 提供缓冲功能。
writer 的主要写方法:
-
public void write(int c) throws IOException; //写单个字符
-
public void write(char cbuf[]) throws IOException; //将字符数组 cbuf[] 写到输出流 。
-
public abstract void write(char cbuf[],int off,int len) throws IOException; //将字符数组cbuf[]中的从索引为off的位置处开始的len个字符写入输出流 。
-
public void write(String str) throws IOException; //将字符串str中的字符写入输出流 。
-
public void write(String str,int off,int len) throws IOException; //将字符串 str 中从索引 off 开始处的 len 个字符写入输出流 。
3、使用方法
3.1、FileOutputStream写文件、FileInputStream读文件
分别为 单个字节写、字节数字写、单个字节读取、字节数组读取、一次性读取:
public class OutputStreamTest {
public static void main(String[] args) throws IOException {
writeFile(); //单个字节写、字节数字写
readFile1();//单个字节读取
readFile2();//字节数组读取
readFile3();//一次性读取
}
static void writeFile() throws IOException {
//1、第一种方法写,单个字节写
//会自动创建文件,目录不存在会报错, true 表示 追加写,默认是false
FileOutputStream fileOutputStream = new FileOutputStream(“F:\hello.txt”, false);
//往文件里面一个字节一个字节的写入数据
fileOutputStream.write((int) ‘H’);
fileOutputStream.write((int) ‘a’);
fileOutputStream.write((int) ‘C’);
//2、第二种方法写 字节数组写
String s = " HelloCoder";
//入文件里面一个字节数组的写入文件,文件为UTF_8格式
fileOutputStream.write(s.getBytes(StandardCharsets.UTF_8));
//刷新流
fileOutputStream.flush();
//关闭流
fileOutputStream.close();
}
static void readFile1() throws IOException {
//1、第一种读的方法,但字节读
System.out.println(“------一个字节读------”);
//传文件夹的名字来创建对象
FileInputStream fileInputStream = new FileInputStream(“F:\hello.txt”);
int by = 0;
//一个字节一个字节的读出数据
while ((by = fileInputStream.read()) != -1) {
System.out.print((char) by);
}
//关闭流
fileInputStream.close();
}
static void readFile2() throws IOException {
//2、第二种读的方法,字节数组读
System.out.println();
System.out.println(“------字节数组读------”);
FileInputStream fileInputStream = new FileInputStream(“F:\hello.txt”);
//通过File对象来创建对象
fileInputStream = new FileInputStream(new File(“F:\hello.txt”));
int by = 0;
byte[] bytes = new byte[10];
//一个字节数组的读出数据,高效
while ((by = fileInputStream.read(bytes)) != -1) {
for (int i = 0; i < by; i++) {
System.out.print((char) bytes[i]);
}
}
//关闭流
fileInputStream.close();
}
static void readFile3() throws IOException {
//3、第三种读方法,一次性读
System.out.println();
System.out.println(“------一次性读文件------”);
FileInputStream fileInputStream = new FileInputStream(“F:\hello.txt”);
fileInputStream = new FileInputStream(new File(“F:\hello.txt”));
//一次性读文件
int iAvail = fileInputStream.available();
int by = 0;
byte[] bytesAll = new byte[iAvail];
while ((by = fileInputStream.read(bytesAll)) != -1) {
for (int i = 0; i < by; i++) {
System.out.print((char) bytesAll[i]);
}
}
fileInputStream.close();
}
}
输出:
------一个字节读------
HaC HelloCoder
------字节数组读------
HaC HelloCoder
------一次性读文件------
HaC HelloCoder
这里介绍了三种方法读一个文件,详细的介绍都写在了注释里。
⚠️ 字符串如果包含中文,就会出现乱码,这是因为FileOutputStream是字节流,将文本按字节写入。
3.2、FileWriter写文件、FileReader读文件
分别为 字符串写、单字符读、字符数组读:
public class ReaderTest {
public static void main(String[] args) throws IOException {
write(); //字符串写
read1();//
read2();//
}
static void write() throws IOException {
FileWriter fileWriter = new FileWriter(“F:\Hello1.txt”);
//为防止乱码,可以这样写,字符流和字节流互转
// Writer fileWriter = new BufferedWriter(new OutputStreamWriter(
// new FileOutputStream(“F:\Hello1.txt”), StandardCharsets.UTF_8));
fileWriter.write(“今天打工你不狠,明天地位就不稳\n” +
“今天打工不勤快,明天社会就淘汰”);
// 如果没有刷新,也没有关闭流的话 数据是不会写入文件的
fileWriter.flush();
fileWriter.close();
}
static void read1() throws IOException {
System.out.println(“------一个一个char读-------”);
FileReader fileReader = new FileReader(“F:\Hello1.txt”);
int ch = 0;
String str = “”;
//一个一个char读
while ((ch = fileReader.read()) != -1) {
str += (char) ch;
}
System.out.println(str);
}
static void read2() throws IOException {
System.out.println(“------char数组[]读-------”);
FileReader fileReader = new FileReader(new File(“F:\Hello1.txt”));
int len = 0;
char[] chars = new char[10];
while ((len = fileReader.read(chars)) != -1) {
//这种读有误
// System.out.print(new String(chars));
System.out.print((new String(chars, 0, len)));
}
fileReader.close();
}
}
输出:
------一个一个char读-------
今天打工你不狠,明天地位就不稳
今天打工不勤快,明天社会就淘汰
------char数组[]读-------
今天打工你不狠,明天地位就不稳
今天打工不勤快,明天社会就淘汰
FileWriter
、FileReader
可以用来读写一个含中文字符的文件。
注意点:
1、流转换
// Writer fileWriter = new BufferedWriter(new OutputStreamWriter(
// new FileOutputStream(“F:\Hello1.txt”), StandardCharsets.UTF_8));
这里其实是把字节流转换为字符流,用来解决乱码。
2、读的位置
这里的写法需要注意,因为这里读写是一次性读10个char类型的字符,如果换成以下
int len = 0;
char[] chars = new char[10];
while ((len = fileReader.read(chars)) != -1) {
//不能这样写
System.out.print(new String(chars));
//System.out.print((new String(chars, 0, len)));
}
则输出:
------char数组[]读-------
今天打工你不狠,明天地位就不稳
今天打工不勤快,明天社会就淘汰勤快,明天社会就淘
可以看到输出不正确,因为一次性读10个char,
第一次读的是 今天打工你不狠,明天
第二次读的是 地位就不稳\n今天打工
第三次读的是 不勤快,明天社会就淘
第四次输出是 汰勤快,明天社会就淘
,其实这一次它只读了汰
一个字符,其中 勤快,明天社会就淘
是上一个数组的内容,因为它是已存在在数组的旧数据。
所以需要new String(chars, 0, len)
,len
是这次读到的字符长度,只需要截取这次的字符即可。
以上这两个例子中,还需要注意的几个地方:
1、只有在写文件的时候才需要flush()
方法,而读是不需要的。
2、读、写 完毕都需要调用close()
方法关闭流。
3、单个字节、字符读写效率较慢,建议使用字节、字符数组读取。
3.3、BufferedInputStream、BufferedOutputStream 缓冲字节流
BufferedInputStream
是带缓冲区的,在复制、移动文件操作会快一点。
建议使用缓冲字节流这不是普通字节流,但构造方法入参还是InputStream和OutputStream。
Java使用IO 读取文件时,会进入核心态,在调用驱动进行IO,本身就会缓存在系统级别的,当你第二次读取时,会由用户态进入核心态,读取系统缓存。BufferedInputStream
就一次性读取较多,缓存起来。
这样下次就从缓存中读,而不用在用户态和核心态之间切换,从而提升效率。
eg:
public class InputStrem与BufferenInputStream复制文件 {
public static void main(String[] args) throws IOException {
useInputStreamCopyFile(); //缓冲流复制文件
useBufferenInputStream(); //普通流复制文件
}
static void useInputStreamCopyFile() throws IOException {
File file = new File(“F:\杨超越.png”);
InputStream is = new FileInputStream(file);
File file2 = new File(“F:\杨超越_copy.png”);
OutputStream os = new FileOutputStream(file2);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
os.write(bytes);
}
is.close();
os.close();
}
static void useBufferenInputStream() throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(“F:\杨超越.png”));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(“F:\杨超越_copy2.png”));
int len = 0;
byte[] bytes = new byte[1024];
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes, 0, len);
}
bos.close();
bis.close();
}
}
结果输出:
3.4、BufferedReader、BufferedWriter 字符缓冲流
BufferedReader
有一个好处,就是它提供了readline()
、newLine()
方法,可以按行读取文件。
eg:
public class BufferedReaderTest {
public static void main(String[] args) throws IOException {
useInputStreamCopyFile(); //这种方法适用于任何文件
//下面两种方法copy的文件变大了,因为是使用字符流处理的
useBufferedReaderCopyFile(); //这种方法只适用于字符文件
useFileReaderCopyFile(); //这种方法一步到位,只适用于字符文件
}
static void useInputStreamCopyFile() throws IOException {
File file = new File(“F:\Hello1.txt”);
InputStream is = new FileInputStream(file);
File file2 = new File(“F:\Hello1_copy1.txt”);
OutputStream os = new FileOutputStream(file2);
int len = 0;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
os.write(bytes, 0, len);
}
is.close();
os.close();
}
static void useBufferedReaderCopyFile() throws IOException {
File file = new File(“F:\Hello1.txt”);
InputStream is = new FileInputStream(file);
Reader reader = new InputStreamReader(is);
//创建字符流缓冲区,BufferedReader 的构造入参是一个 Reader
BufferedReader bufferedReader = new BufferedReader(reader);
File file2 = new File(“F:\Hello1_copy2.txt”);
OutputStream os = new FileOutputStream(file2);
Writer writer = new OutputStreamWriter(os);
//创建字符流缓冲区,BufferedWriter 的构造入参是一个 Writer
BufferedWriter bufferedWriter = new BufferedWriter(writer);
String line = null;
//readLine()方法 是根据\n 换行符读取的
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
//这里要加换行
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
static void useFileReaderCopyFile() throws IOException {
//使用FileReader、FileWriter 一步到位
Reader reader = new FileReader(“F:\Hello1.txt”);
BufferedReader bufferedReader = new BufferedReader(reader);
Writer writer = new FileWriter(“F:\Hello1_copy3.txt”);
BufferedWriter bufferedWriter = new BufferedWriter(writer);
String line = null;
while ((line = bufferedReader.readLine()) != null) {
bufferedWriter.write(line);
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
4、close() 与flush()
先上个例子:
public class FlushTest {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader(“F:\Hello1.txt”); //大文件
FileWriter fileWriter = new FileWriter(“F:\Hello2.txt”);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
r.close();
}
}
4、close() 与flush()
先上个例子:
public class FlushTest {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader(“F:\Hello1.txt”); //大文件
FileWriter fileWriter = new FileWriter(“F:\Hello2.txt”);
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-ivWM1iA0-1715706810811)]
[外链图片转存中…(img-QVL6zGGg-1715706810811)]
[外链图片转存中…(img-MFxKtdwA-1715706810812)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!