在java中对数据流的操作分为输入与输出两种方式,而且针对此操作提供了一下两类支持。
- 字节流(JDK 1.0开始提供):InputStream(输入字节流)、OutputStream(输出字节流);
- 字符流(JDK 1.1开始提供):Reader(输入字符流)、Writer(输出字符流)。
一、字节流
输出字节流 OutputStream
No. | 方法 | 类型 | 描述 |
1 | public void close() throws IOException | 普通 | 关闭字节流 |
2 | public void flush() throws IOException | 普通 | 强制刷新 |
3 | public abstract void write(int b) thorws IOException | 普通 | 输出单个字节 |
4 | public void write(byte[] b) throws IOException | 普通 | 输出全部字节数组数据 |
5 | public void write(byte[] b,int off,int len) throws IOExcption | 普通 | 输出部分字节数组数据 |
注:OutputStream类是个抽象类,同时实现了Closeable和Flushable接口,而Closeable继承了AutoCloseable接口,因此当使用完OutputStream后即使不手动关闭资源,系统也会自动将资源关闭
OutputStream类本身是一个抽象类,如果需要进行文件操作,可以使用FileOutputStream子类完成。
No. | 方法 | 类型 | 描述 |
1 | public FileOutputStream(File file) throws FileNotFoundException | 构造 | 将内容输出到指定路径,如果文件已存在则使用新的内容覆盖旧的内容 |
2 | public FileOutputStream(File file,boolean append) throws FileNotFoundException | 构造 | 如果将布尔参数设置为true,则表示追加新的内容到文件中 |
1.使用字节输出流将设置好的内容输出到指定文件中
package com.tjut.streamTest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class StreamTest01 {
public static void main(String[] args) throws IOException {
//定义要输出文件的路径
File file = new File("d:" + File.separator + "Demo" + File.separator + "Hello" + File.separator + "test.txt");
//此时由于目录不存在,所以文件不能输出,应该首先创建目录
if(!file.getParentFile().exists()) {
file.getParentFile().mkdirs();
}
//利用OutputStream向文件输出信息时如果文件不存在,则会自动创建(不需要用户手动调用createNewFile()方法)
OutputStream output = new FileOutputStream(file);
String str = "没有月色的夜里,萤火虫用心点亮漫天的星";
byte data[] = str.getBytes();
output.write(data);
output.close();
}
}
读者可以尝试使用单个字节的方式输出
for(int i = 0;i < data.length;i++) {
output.write(data[i]);
}
或者输出部分字节数组的内容
output.write(data,6,6);
输入字节流 InputStream
InputStream的可以对比OutputStream来学习,同样是抽象类,也不需要手动关闭资源。
No. | 方法 | 类型 | 描述 |
1 | public void close() throws IOException | 普通 | 关闭字节输入流 |
2 | public abstract int read() throws IOException | 普通 | 读取单个字节 |
3 | public int read(byte[] b) throws IOException | 普通 | 将数据读取到字节数组中,同时返回读取的数据长度 |
4 | public int read(byte[] b,int off,int len) throws IOException | 普通 | 将数据读取到部分字节数组中,同时返回读取的数据长度 |
注:read()方法读到结尾后会返回-1
InputStream本身是一个抽象类,需要使用FileInputStream类来实现相应的文件操作
No. | 方法 | 类型 | 描述 |
1 | public FileInputStream(File file) throws FileNotFoundException | 普通 | 设置要读取文件数据的路径 |
2.使用字节输入流读取指定文件中的数据,并将其输出到控制台
package com.tjut.streamTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
public class StreamTest02 {
public static void main(String[] args) throws IOException {
//1.定义要输入文件的路径
File file = new File("d:" + File.separator + "Demo" + File.separator + "Hello" + File.separator + "test.txt");
if(file.exists()) {//判断文件是否存在
//2.使用InputStream进行读取
InputStream input = new FileInputStream(file);
byte data[] = new byte[1024];//准备一个1024的字节数组
int len = input.read(data);//3.进行数据读取,将内容保存到字节数组中
input.close();//4.关闭输入流
System.out.println(new String(data,0,len));
}
}
}
你也可以尝试使用while循环,每次读取一个字节
int foot = 0;
int temp = 0;
while((temp = input.read()) != -1) {
data[foot++] = (byte)temp;
}
二、字符流
字符输出流Writer
Writer是一个抽象类,实现了Appendable、Closeable(父接口AutoCloseable)和Flushable接口,因此也不需要手动关闭资源。利用Writer类可以实现字符数组(包含了字符串)的输出
No. | 方法 | 类型 | 描述 |
1 | public void close() throws IOException | 普通 | 关闭字符输出流 |
2 | public void flush() throws IOException | 普通 | 强制刷新 |
3 | public Writer append(CharSequence csq) throws IOException | 普通 | 追加数据 |
4 | public void write(String str) throws IOException | 普通 | 输出字符串数据 |
5 | public void write(char[] cbuf) throws IOException | 普通 | 输出字符数组数据 |
Writer是一个抽象类,要针对文件内容进行输出,可以使用java.io.FileWriter类实现Writer类对象的实例化操作。
No. | 方法 | 类型 | 描述 |
1 | public FileWriter(File file) throws IOException | 构造 | 设置输出文件 |
2 | public FileWriter(File file,boolean append) throws IOException | 构造 | 设置输出文件以及是否进行数据追加 |
3.使用字符输出流将特定内容写入指定文件中
package com.tjut.streamTest;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class StreamTest03 {
public static void main(String[] args) throws IOException {
//1.定义要输入文件的路径
File file = new File("d:" + File.separator + "Demo" + File.separator + "Hello" + File.separator + "test.txt");
if(!file.getParentFile().exists()) {//判断目录是否存在
file.getParentFile().mkdirs();//创建文件目录
}
Writer write = new FileWriter(file);//2.实例化Writer对象
String str = "美丽的梦和美丽的诗一样 \r\n" + "都是可遇而不可求的 \r\n" +
"常常在最没能料到的时刻里出现";
write.write(str);//3.输出字符串数据
write.close();//4.关闭输出流
}
}
字符输入流Reader
java.io.Reader类是实现字符数据输入的操作类,在进行数据读取时可以不使用字节数据,而直接依靠字符数据(方便处理中文)进行操作。
No. | 方法 | 类型 | 描述 |
1 | public void close() throws IOException | 普通 | 关闭字符输入流 |
2 | public int read() throws IOException | 普通 | 读取单个字符 |
3 | public int read(char[] cbuf) throws IOException | 普通 | 读取字符到字符数组中,返回读取长度 |
4 | public long skip(long n) throws IOException | 普通 | 跳过字节长度 |
注:Reader类实现了Closeable(父接口为AutoCloseable)和Readable接口,因此不需要手动关闭资源
Writer类中存在直接输出字符串的操作,而Reader类中并没有直接返回字符串的操作,这是因为输出数据时可以采用追加模式,导致文件变得非常庞大。如果在Reader类中提供了直接读取全部数据的方式,就有可能造成内存溢出问题。
Reader类是一个抽象类,要实现文件数据的字符流读取,可以利用FileReader子类为Reader对象实例化。
No. | 方法 | 类型 | 描述 |
1 | public FileReader(File file) throws FileNotFoundException | 构造 | 定义要读取的文件路径 |
4.使用Reader从指定文件中读取数据
package com.tjut.streamTest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
public class StreamTest04 {
public static void main(String[] args) throws IOException {
//1.定义要输入文件的路径
File file = new File("d:" + File.separator + "Demo" + File.separator + "Hello" + File.separator + "test.txt");
if(file.exists()) {
Reader reader = new FileReader(file);//2.为Reader类对象实例化
char data[] = new char[1024];
int len = reader.read(data);//3.进行数据读取
reader.close();//4.关闭输入流
System.out.println(new String(data,0,len));
}
}
}
字节流与字符流的区别
字节流直接与终端文件进行数据交互,字符流需要将数据经过缓冲区处理才与终端文件数据交互。在使用OutputStream输出数据时即使最后没有关闭输出流,内容也可以正常输出,但是反过来如果使用的是字符输出流Writer,在执行到最后如果不关闭输出流,就表示在缓冲区中处理的内容不会被强制性清空,所以就不会输出数据。如果有特殊情况不能关闭字符输出流,可以使用flush()方法强制清空缓冲区。
5.强制清空字符流缓冲区
package com.tjut.streamTest;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class StreamTest05 {
public static void main(String[] args) throws IOException {
//1.定义要输出文件的路径
File file = new File("d:" + File.separator + "Demo" + File.separator + "Hello" + File.separator + "test.txt");
if(!file.getParentFile().exists()) {//判断目录是否存在
file.getParentFile().mkdirs();//创建文件目录
}
Writer writer = new FileWriter(file);//2.实例化Writer类对象
String str = "我喜欢那样的梦 \r\n" +
"在梦里 一切都可以重新开始 \r\n" +
"一切都可以慢慢解释 \r\n" +
"心里甚至还能感觉到所有被浪费的时光 \r\n" +
"竟然都能重回时的狂喜和感激";
writer.write(str);//3.输出字符串数据
writer.flush();//强制刷新缓冲区
}
}
注:在开发中,如果要处理中文时应优先考虑字符流,如果没有中文问题,建议使用字节流。
三、转换流
虽然字节流和字符流表示两种不同的数据流操作,但是这两种流彼此间是可以实现相互转化的,虽然转换流的使用情况并不多。
名称 | InputStreamReader | OutputStreamReader |
定义结构 | public class InputStreamReader extends Reader | public class OutputStreamWriter extends Writer |
构造方法 | public InputStreamReader(InputStream in) | public OutputStreamWriter(OutputStream out) |
6.将字节输出流(OutputStream)转换为字符输出流(Writer)
package com.tjut.streamTest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
public class StreamTest06 {
public static void main(String[] args) throws IOException {
//1.定义要输出文件的路径
File file = new File("d:" + File.separator + "Demo" + File.separator + "Hello" + File.separator + "test.txt");
if(!file.getParentFile().exists()) {//判断目录是否存在
file.getParentFile().mkdirs();//创建目录
}
OutputStream output = new FileOutputStream(file);//字节流
//将OutputStream类对象传递给OutputStreamWriter类的构造方法,而后向上转型为Writer
Writer writer = new OutputStreamWriter(output);
String str = "胸怀中满溢著幸福\r\n" +
"只因为你就在我眼前\r\n" +
"对我微笑 一如当年\r\n" +
"我真喜欢那样的梦";
writer.write(str);//Writer类的方法
writer.flush();
writer.close();
}
}
文件操作类的继承结构如下:
通过继承结构可以发现,FileWriter与FileReader都是转换流的子类,也就证明所有要读取的文件数据都是字节数据,所有 的字符都是在内存中处理后形成的。