流是个抽象的概念,是对输入输出设备的抽象,Java程序中,对于数据的输入输出都是以流的方式进行。设备可以是文件、网络、内存等。
I/O字节流
InputStream字节输入流
OutputStream字节输出流
用于以字节的形式读取和写入数据
以字节流的形式读取文件内容
InputStream 是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.lfh.learn;
import java.io.File; import java.io.FileInputStream; import java.io.IOException;
public class Learn { public static void main(String[] args) {
try { File file = new File("D:\\Desktop\\1.txt"); FileInputStream inputStream = new FileInputStream(file); byte[] all = new byte[(int) file.length()]; inputStream.read(all); for (byte b : all) { System.out.println(b); } inputStream.close();
} catch (IOException e) { e.printStackTrace(); }
}
}
|
文件内容
读取到的内容
以字节流的形式向文件写入数据
OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据
注: 如果文件D:\Desktop\1.txt不存在,写出操作会自动创建该文件。
但是如果是文件 D:\Desktop\xyz\1.txt,而目录xyz又不存在,会抛出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com.lfh.learn;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException;
public class Learn { public static void main(String[] args) {
try { File file = new File("D:\\Desktop\\1.txt"); byte[] all = new byte[] { 98, 99 }; FileOutputStream onputStream = new FileOutputStream(file); onputStream.write(all); System.out.println("写入成功"); onputStream.close();
} catch (IOException e) { e.printStackTrace(); }
}
}
|
运行后文件中的内容
关闭流的方式
所有的流,无论输入流还是输出流,使用完毕之后,都应该关闭。如果不关闭,会产生对资源占用的浪费。当量比较大的时候,回影响到争正常的业务开展。
(1)在try中关闭(最容易错的方式,不推荐使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package stream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class TestStream { public static void main(String[] args) { try { File f = new File("D:\\Desktop\\1.txt"); FileInputStream fis = new FileInputStream(f); byte[] all = new byte[(int) f.length()]; fis.read(all); for (byte b : all) { System.out.println(b); } fis.close(); } catch (IOException e) { e.printStackTrace(); } } }
|
这种方式存在弊端,即:如果文件不存在或者读取的时候抛出异常,那么就不会执行到关闭流的那一行代码,这就存在巨大的资源隐患。
(2)在finally中关闭(标准的关闭流方式)
- 首先把流的引用声明在try外面,如果声明在里面的话,其作用域无法到达finally。
- 在finally关闭之前,要先判断该引用是否为空
- 关闭的时候,需要再进行以此try catch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| package com.lfh.learn;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException;
public class Learn { public static void main(String[] args) { FileOutputStream onputStream = null; try { File file = new File("D:\\Desktop\\1.txt"); byte[] all = new byte[] { 98, 99 }; onputStream = new FileOutputStream(file); onputStream.write(all); System.out.println("写入成功");
} catch (IOException e) { e.printStackTrace(); } finally { if (onputStream != null) { try { onputStream.close(); } catch (IOException e) { e.printStackTrace(); } }
}
} }
|
(3)使用try()的方式关闭
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭。这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.lfh.learn;
import java.io.File; import java.io.FileOutputStream; import java.io.IOException;
public class Learn { public static void main(String[] args) { File file = new File("D:\\Desktop\\1.txt"); try (FileOutputStream onputStream = new FileOutputStream(file)) { byte[] all = new byte[] { 98, 99 }; onputStream.write(all); System.out.println("写入成功");
} catch (IOException e) { e.printStackTrace(); }
}
}
|
I/O字符流
Reader字符输入流
Writer字符输出流
专门用于字符的形式读取和写入数据
使用字符流读取文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.lfh.learn;
import java.io.File; import java.io.FileReader; import java.io.IOException;
public class Learn { public static void main(String[] args) { File file = new File("D:\\Desktop\\1.txt"); try (FileReader fileReader = new FileReader(file)) { char[] content = new char[(int) file.length()]; fileReader.read(content); for (char c : content) { System.out.println(c); } } catch (IOException e) { e.printStackTrace(); }
}
}
|
文件内容
读取到的内容
使用字符流把字符写入到文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.lfh.learn;
import java.io.File; import java.io.FileWriter; import java.io.IOException;
public class Learn { public static void main(String[] args) { File file = new File("D:\\Desktop\\1.txt"); try (FileWriter fileWriter = new FileWriter(file)) { char[] content = new char[] {'L','L','L','L'}; fileWriter.write(content); System.out.println("写入成功"); } catch (IOException e) { e.printStackTrace(); }
} }
|
写入后的文件内容
I/O缓存流
以介质是硬盘为例,字节流和字符流都存在弊端 ,在每一次读写的时候,都会访问硬盘。如果读写的频率比较高,那么性能表现不佳。为了解决该弊端,则采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中去读取。
缓存流在写入数据的时候,会先把数据写入到缓存区中,直到缓存区达到一定量,才把这些数据,一起写到硬盘中。按照这种方式,可以大大减少IO操作。
使用缓存流读取数据
缓存字符输入流 BufferedReader 可以一次读取一行数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package com.lfh.learn;
import java.io.BufferedReader; import java.io.File; import java.io.FileReader;
public class Learn { public static void main(String[] args) { File file = new File("D:\\Desktop\\1.txt");
try (FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader);) { while (true) { String line = bufferedReader.readLine(); if (null == line) break; System.out.println(line); } } catch (Exception e) { e.printStackTrace(); } } }
|
值得注意的是,缓存流必须建立在一个存在的流之上才能使用。
使用缓存流写出数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com.lfh.learn;
import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter;
public class Learn { public static void main(String[] args) { File file = new File("D:\\Desktop\\1.txt");
try (FileWriter fileWriter = new FileWriter(file); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);) { bufferedWriter.write("123"); } catch (Exception e) { e.printStackTrace(); } } }
|
之后文件内容就变为了123
有时候,需要立即把数据写入到硬盘,而不是等缓存满了才写进去,这时候就要用到flush
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.lfh.learn;
import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter;
public class Learn { public static void main(String[] args) { File file = new File("D:\\Desktop\\1.txt");
try (FileWriter fileWriter = new FileWriter(file); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);) { bufferedWriter.write("123"); bufferedWriter.flush(); bufferedWriter.write("123"); bufferedWriter.flush(); } catch (Exception e) { e.printStackTrace(); } } }
|
写入后的文件内容
I/O数据流
DataInputStream 数据输入流
DataOutputStream 数据输出流
直接进行字符串的读写
使用数据流的writeUTF()和readUTF() 可以进行数据的格式化顺序读写
如本例,通过DataOutputStream 向文件顺序写出 布尔值,整数和字符串。 然后再通过DataInputStream 顺序读入这些数据。
注: 要用DataInputStream 读取一个文件,这个文件必须是由DataOutputStream 写出的,否则会出现EOFException,因为DataOutputStream 在写出的时候会做一些特殊标记,只有DataInputStream 才能成功的读取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| package com.lfh.learn;
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream;
public class Learn {
public static void read(File file) { try (FileInputStream fileInputStream = new FileInputStream(file); DataInputStream dataInputStream = new DataInputStream(fileInputStream);) {
boolean readBoolean = dataInputStream.readBoolean(); int readInt = dataInputStream.readInt(); String readUTF = dataInputStream.readUTF();
System.out.println("读到的布尔值为:" + readBoolean + ""); System.out.println("读到的整型为:" + readInt + ""); System.out.println("读到的字符串为:" + readUTF); } catch (Exception e) { e.printStackTrace(); } }
public static void write(File file) { try (FileOutputStream fileOutputStream = new FileOutputStream(file); DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);) { dataOutputStream.writeBoolean(true); dataOutputStream.writeInt(6); dataOutputStream.writeUTF("刘方涵"); } catch (Exception e) { e.printStackTrace(); } }
public static void main(String[] args) { File file = new File("D:\\Desktop\\1.txt"); write(file); read(file); } }
|
写入后的文件内容
代码运行输出