Java 基础之常见的输入输出流以及基本使用
共计 6966 个字符,预计需要花费 18 分钟才能阅读完成。
介绍
流是用了读取和写出数据的对象,下面是常见的一些对象即使用方法。
1. 字节流
-
InputStream:用于从字节流中读取数据。
InputStream 为抽象类,常见的继承类:FileInputStream、BufferedInputStream、DataInputStream、ObjectInputStream。
-
OutputStream:用于向字节流中写入数据。
OutputStream 同样为抽象类,常见继承类:FileOutputStream、BufferedOutputStream、DataOutputStream、ObjectOutputStream
2. 字符流
-
Reader:用于从字符流中读取数据。
Reader 也为抽象类,常见的继承类:FileReader、InputStreamReader、BufferedReader、StringReader。
-
Writer:用于向字符流中写入数据。
Writer 为抽象类,常见的继承类:FileWriter、OutputStreamWriter、BufferedWriter、StringWriter。
3. 缓冲流
缓冲流内置了缓冲区,将磁盘内容先读取到缓冲区即内存中,一般默认大小为 8K,获取字节或字符时直接从内存中取出,减少了和磁盘打交道的次数。
-
BufferedInputStream:提供了缓冲功能的字节输入流。
-
BufferedOutputStream:提供了缓冲功能的字节输出流。
-
BufferedReader:提供了缓冲功能的字符输入流。
-
BufferedWriter:提供了缓冲功能的字符输出流。
4. 文件流
-
FileInputStream:用于从文件中读取数据的字节流。
-
FileOutputStream:用于向文件中写入数据的字节流。
-
FileReader:用于从文件中读取数据的字符流。
-
FileWriter:用于向文件中写入数据的字符流。
5. 转换流
-
InputStreamReader:将字节流转换为字符流的转换流。
-
OutputStreamWriter:将字符流转换为字节流的转换流。
6. 数据流
支持读写基本数据类型和字符串,但是不支持读写对象类型。
-
DataInputStream:用于读取基本数据类型和字符串的流。
-
DataOutputStream:用于写入基本数据类型和字符串的流。
7. 对象流
支持基本类型和字符串的读写,同时也从支持对实现了Serializable 接口的对象进行序列化和反序列化。
-
ObjectInputStream:用于读取对象的流。
-
ObjectOutputStream:用于写入对象的流。
基本使用
以下内容是对上面各种输入输出流的一些测试方法:
public class IOTest {
/**
* 字节流 InputStream OutputStream
* 1. 利用输入流,读取 file.txt, 将字符打印在控制台
* 2. 利用输出流,复制 file.txt 里面的内容,追加到 file_copy.txt
*/
@Test
public void test1() throws IOException {
String inputFile = "file/io/file.txt";
String outPutFile = "file/io/file_copy.txt";
initFileTxt(inputFile); // 初始化文件内容为:你好啊amjun
// try-with-resources 语句
try (InputStream inputStream = new FileInputStream(inputFile);
OutputStream outputStream = new FileOutputStream(outPutFile);) {
int byteData;
while ((byteData = inputStream.read()) != -1) {
// byteData 是读取到的单个字节,因为这种读取方式是单个字符读取的
// 打印中文时会乱码,因为中文在utf-8中是三个字节为一个字符
System.out.println(byteData + " " + (char)byteData);
outputStream.write(byteData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 使用缓冲区进行数据读取
* 1. 创建一个字节数组作为缓冲区
* 2. 输入流读取字节时,将字节读入缓冲区
* 3. 打印时,通过缓冲区的内容创建一个字符串
* 4. 写入文件时,将缓冲区的内容一次性写入
*/
@Test
public void test2(){
String inputFile = "file/io/file.txt";
String outPutFile = "file/io/file_buffer_copy.txt";
initFileTxt(inputFile); // 初始化文件内容为:你好啊amjun
try (InputStream inputStream = new FileInputStream(inputFile);
OutputStream outputStream = new FileOutputStream(outPutFile);) {
// 创建临时字节数组缓冲区
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
// bytesRead 是读取到的字节数,当字节少于1024时,一次性全部读取并打印,所以打印不会乱码
System.out.print(new String(buffer, 0 , bytesRead));
// 字节数为 14,因为3中文+5英文,中文3个字节1个字符,英文1个字节1个字符
System.out.println("\n读取到的字节数:" + bytesRead);
outputStream.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字节缓冲流 BufferedInputStream BufferedOutputStream
* 引入了缓冲区,缓冲区的存在可以减少和磁盘之间的交互次数,提高读写效率。有需要可以打印时间进行测试
* 缓冲区会一次读取一定量的数据,然后在内存中进行操作,直到缓冲区被填满或者操作完成后再写回磁盘。
*/
@Test
public void test3(){
String inputFile = "file/io/file.txt";
String outPutFile = "file/io/file_buffer2_copy.txt";
initFileTxt(inputFile); // 初始化文件内容为:你好啊amjun
try (BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(inputFile));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(outPutFile))) {
// 创建临时字节数组缓冲区
int bytesRead;
while ((bytesRead = bufferedInputStream.read()) != -1) {
// 该乱码还是乱码,因为即使内部实现了缓冲区,但是读取的字节还是一个个读取出来的,但是字节的读取是在内存中读的,而不是在磁盘中
System.out.println(bytesRead + " " + (char)bytesRead);
bufferedOutputStream.write(bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字符流转换流 InputStreamReader OutputStreamWriter
* 1. 先将文件读取为字节流,然后用字符流包装,输出流文件也是如此
* 2. 创建一个字符数组作为缓冲区
* 3. 将文件读取到字符缓冲区
* 4. 将字符缓冲区的内容打印和写入
*/
@Test
public void test4(){
String inputFile = "file/io/file.txt";
String outPutFile = "file/io/file_buffer_copy.txt";
initFileTxt(inputFile); // 初始化文件内容为:你好啊amjun
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(inputFile));
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(outPutFile));) {
// 创建临时字符数组缓冲区
char[] buffer = new char[1024];
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
// 将读取到的字符写入控制台,由于字符数小于1024,会一次性全部输出
System.out.print(new String(buffer, 0, charsRead));
// 3中文字符+5英文字符
System.out.println("\n读取到的字符数:" + charsRead);
// 将读取的数据追加到目标文件中
writer.write(buffer, 0, charsRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字符缓冲流 BufferedReader BufferedWriter
*/
@Test
public void test5(){
String inputFile = "file/io/file.txt";
String outPutFile = "file/io/file_buffer_copy.txt";
initFileTxt(inputFile); // 初始化文件内容为:你好啊amjun
// 装饰器模式
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile)));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outPutFile)))) {
// 创建临时字符数组缓冲区
char[] buffer = new char[1024];
int charsRead;
while ((charsRead = bufferedReader.read(buffer)) != -1) {
// 将读取到的字符写入控制台,由于字符数小于1024,会一次性全部输出
System.out.print(new String(buffer, 0, charsRead));
// 3中文字符+5英文字符
System.out.println("\n读取到的字符数:" + charsRead);
// 将读取的数据追加到目标文件中
bufferedWriter.write(buffer, 0, charsRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 字符流 FileReader FileWriter
*/
@Test
public void test6() throws IOException {
String inputFile = "file/io/file.txt";
String outPutFile = "file/io/file_buffer_copy.txt";
initFileTxt(inputFile); // 初始化文件内容为:你好啊amjun
try (Reader reader = new FileReader(inputFile);
Writer writer = new FileWriter(outPutFile);) {
// 创建临时字符数组缓冲区
char[] buffer = new char[1024];
int charsRead;
while ((charsRead = reader.read(buffer)) != -1) {
// 将读取到的字符写入控制台,由于字符数小于1024,会一次性全部输出
System.out.print(new String(buffer, 0, charsRead));
// 3中文字符+5英文字符
System.out.println("\n读取到的字符数:" + charsRead);
// 将读取的数据追加到目标文件中
writer.write(buffer, 0, charsRead);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 数据流 DataInputStream DataOutputStream
* 只支持读写基本数据类型和字符串
*/
@Test
public void test7() {
String obgFile = "file/io/data.bin";
try (DataOutputStream dataOutputStream = new DataOutputStream(new FileOutputStream(obgFile))) {
dataOutputStream.writeInt(19);
System.out.println("写入基本数据类型成功...");
} catch (Exception e) {
e.printStackTrace();
}
try (DataInputStream dataInputStream = new DataInputStream(new FileInputStream(obgFile));) {
int i = dataInputStream.readInt();
System.out.println("读取基本类型数据:" + i);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 对象流 ObjectInputStream ObjectOutputStream
* 对象流不能使用字符流进行包装,因为O对象流是基于字节流的,用于写入对象的二进制表示。而字符流主要用于处理字符数据。
*/
@Test
public void test8() {
// 序列化对象
String obgFile = "file/io/obj.bin";
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(obgFile))) {
User user = new User().setName("zhangsan").setAge(18);
objectOutputStream.writeObject(user);
System.out.println("写入对象成功...");
} catch (Exception e) {
e.printStackTrace();
}
// 反序列化对象
try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(obgFile));) {
User user = (User)objectInputStream.readObject();
System.out.println("读取的对象为:" + user);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 初始化文件内容
*/
public void initFileTxt(String outputFile){
try(OutputStream outputStream = new FileOutputStream(outputFile);
OutputStreamWriter writer = new OutputStreamWriter(outputStream)){
String str = "你好啊amjun";
// 将字符串以字节数组方式写入文件
//byte[] byteArray = str.getBytes("UTF-8");
//outputStream.write(byteArray);
// 将文件以字符数组写入文件
char[] charArray = str.toCharArray();
writer.write(charArray);
}catch (IOException e){
}
}
}
@Data
@Accessors(chain = true)
class User implements Serializable{
public String name;
public int age;
}
提醒:本文发布于402天前,文中所关联的信息可能已发生改变,请知悉!
Tips:清朝云网络工作室