JavaIO
源码我已放入gitee仓库:https://gitee.com/xu-nuojie/java-io/tree/master/src/main/java/com/xnj/fileIODemo
File类对应 ——》filedemo包
字节输入流/字节输出流/文件复制 ——》file_byte_stream_demo包
字符输入流/字符输出流 ——》file_char_stream_demo包
资源释放 ——》trycachdemo包
File与IO流
File是java.io.包下的类,File类的对象,用于代表当前操作系统的文件(文件或文件夹)。
- 常见的方法:获取文件信息(大小,文件名,修改时间),判断文件类型,创建/删除文件/文件夹…
- 注意:File类只能对文件本身进行操作,不能读写文件里面存储的数据。
IO流是java.io.包下的类,用于读写数据,分为输入流和输出流。
- 用于读写数据的(可以读写文件,或网络中的数据…)
- 输入流:从数据源读取数据到程序中,如:从键盘读取数据,从文件读取数据,从网络读取数据…
- 输出流:从程序中写出数据到数据目的地,如:向屏幕输出数据,向文件输出数据,向网络输出数据…
对比
- File:代表文本
- IO流:读写数据
File类
文件类型,文件信息
File提供了的 判断文件的类型、获取文件信息功能
方法名称 | 说明 |
---|---|
public boolean exists() | 判断当前文件对象,对应的文件路径是否存在,存在返回true |
public boolean isFile() | 判断当前File对象是否代表一个文件,是文件返回true |
public boolean isDirectory() | 判断当前File对象是否代表一个文件夹,是文件夹返回true |
public String getName() | 获取文件的名称(包含后缀) |
public long length() | 获取文件的大小,返回字节个数 |
public long lastModified() | 获取文件的最后修改时间 |
public String getPath() | 获取创建文件对象时,使用的路径 |
public String getAbsolutePath() | 获取绝对路径 |
public String getParent() | 获取当前File对象代表的文件的父目录的路径 |
示例代码:
- 文件对象、是否存在、字节大小,绝对路径/相对路径
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
36public class FileTest {
public static void main(String[] args) {
// File可以代表一个文件,
/* 文件路径符的表达方式有三种
File file1 = new File("D:\\测试文件1.txt"); 使用双反斜杠,斜杠是转义字符,需要使用双反斜杠
File file1 = new File("D:/测试文件1.txt"); 使用反斜杠,反斜杠是普通字符,不需要使用双反斜杠
File file1 = new File("D:"+File.separator+"测试文件1.txt"); 使用File.separator,根据系统自动选择
*/
File file1 = new File("D:\\测试文件1.txt");
// 判断文件是否存在
System.out.println(file1.exists());// true
// 文件的字节大小
System.out.println(file1.length()); // 14
// 即使文件不存在,也可以创建文件对象
File file2 = new File("D:\\测试文件2.txt");
System.out.println(file2.exists()); // false
// File也可以代表一个文件夹
File dir = new File("D:/测试文件夹");
// 输出的是文件夹自身的大小,并不加上文件夹内文件的大小
System.out.println(dir.length()); // 0
/* 绝对路径和相对路径
绝对路径:从盘符开始,一直到文件或者文件夹,使用反斜杠或者双反斜杠
相对路径:从当前目录开始,一直到文件或者文件夹,使用反斜杠或者双反斜杠
下面的例子为java项目src目录下创建了一个test.txt
*/
File file3 = new File("src/test.txt"); // 相对路径
File file4 = new File("D:\\code\\JavaIODemo\\src\\test.txt"); // 绝对路径
System.out.println(file3.length() == file4.length()); // true
}
} - 文件是否存在,是否是文件/文件夹、文件名、大小、修改时间、获取路径
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
34public class FileTest2 {
public static void main(String[] args) {
File file1 = new File("D:\\测试文件夹\\aa.txt");
// 1. 判断文件是否存在
System.out.println(file1.exists()); // true
// 2. 判断是否是文件
System.out.println(file1.isFile()); // true
// 3. 判断是否是目录
System.out.println(file1.isDirectory()); // false
// 4. 获取文件的名字,包括后缀名
System.out.println(file1.getName()); // aa.txt
// 5. 获取文件大小
System.out.println(file1.length()); // 6
// 6. 获取文件的上次修改时间
long time = file1.lastModified(); // 返回1970年1月1日0时0分0秒到当前时间的毫秒数
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time)); // 2025-03-21 15:55:23
// 7. 获取文件的路径,获取创建文件对象时使用的路径
File file2 = new File("D:\\code\\JavaIODemo\\src\\test.txt");
File file3 = new File("src/test.txt");
System.out.println(file2.getPath()); // D:\code\JavaIODemo\src\test.txt
System.out.println(file3.getPath()); // src/test.txt
// 8.获取文件的绝对路径
System.out.println(file3.getAbsolutePath()); // D:\code\JavaIODemo\src\test.txt
}
}
创建/删除文件,文件夹,
File类还提供了创建文件,文件夹的方法,还有删除文件的方法。
方法 | 描述 |
---|---|
public boolean createNewFile() | 创建一个新的空文件 |
public boolean mkdir() | 只能创建一级文件夹,如果父文件夹不存在,则创建失败 |
public boolean mkdirs() | 可以创建多级文件夹,如果父文件夹不存在,则创建父文件夹 |
public boolean delete() | 删除一个文件或空文件夹 |
示例代码
- 创建文件/文件夹,删除文件/文件夹
注意:delete方法只能删除文件和空文件夹,删除后的文件不会进入回收站。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/**
* 创建文件和删除
*/
public class FileTest3 {
public static void main(String[] args) throws IOException {
File file1 = new File("D:/测试文件夹/bb.txt");
File file2 = new File("D:/测试文件夹/aa");
File file3 = new File("D:/测试文件夹/bb/cc/dd");
// 1. 创建一个文件,如果文件存在,则不创建,如果文件不存在,则创建
System.out.println(file1.createNewFile()); // true
// 2. 创建一个文件夹,如果文件夹存在,则不创建,如果文件夹不存在,则创建
// 只会创建一级文件夹,如果父文件夹不存在,则创建失败
System.out.println(file2.mkdir()); // true
// 3. 创建多级文件夹,如果父文件夹不存在,则创建父文件夹
System.out.println(file3.mkdirs()); // true
// 4. 删除文件或文件夹
// 如果文件夹中有文件或文件夹,删除失败
System.out.println(file1.delete()); // true
System.out.println(file2.delete()); // true
File file4 = new File("D:/测试文件夹/bb");
System.out.println(file4.delete()); // false
}
}
遍历文件夹
File类还提供了遍历文件夹的功能
方法 | 描述 |
---|---|
public String[] listFiles() | 获取当前文件夹下的所有的一级文件名称到一个字符串数组中返回 |
public File[] listFiles() | 获取当前文件夹下的所有一级文件对象到一个文件对象数组中返回 |
示例代码: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/**
* 遍历文件夹下的两种方法
*/
public class FileTest4 {
public static void main(String[] args) {
File file = new File("D:/code");
/**
* 方式一:list
* 返回文件和文件夹的字符串数组,String 类型
* 当前文件下的一级文件和文件夹名称
*/
String[] fileList1 = file.list();
for(String f : fileList1){
System.out.println(f); // 打印出来的是文件名,不包含路径
}
/**
* 方式二:listFiles
* 返回文件和文件夹的文件对象数组,File 类型
* 当前文件下的一级文件和文件夹对象
* 注意:如果file是文件,则返回null
* 如果file是空文件夹,则返回空数组
*/
File[] files = file.listFiles();
for(File f : files){
System.out.println(f); // 打印出来的是文件名,包含路径
}
}
}
文件搜索功能
通过递归,获取文件夹下一级文件对象,判断是否是文件,判断文件名是否是搜索目标,这样就能达到搜问目标文件的功能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
48/**
* 文件搜索案例
*/
public class FileSearchDemo {
public static void main(String[] args) {
String filename = "test.txt";
File dir = new File("D:/");
fileSearch(dir, filename);
}
public static void fileSearch(File dir,String filename){
// 1. 拦截非法情况
if(dir == null || !dir.exists() || dir.isFile()){
return ;
}
// 2. 是文件夹,获取其子一级目录的内容
File[] files = dir.listFiles();
if(files != null ){
// 遍历该目录下所有一级文件对象
for(File f : files){// 是文件,判断
if(f.isFile()){
if (f.getName().contains(filename)) {
System.out.println("找到相关文件:"+f.getAbsolutePath());
/**
* 如果文件为.exe文件,我们想启动该文件,
* 那么可以调用Runtime.getRuntime().exec(文件绝对路径);
*/
// try {
// Runtime runtime = Runtime.getRuntime();
// runtime.exec(f.getAbsolutePath());
// } catch (Exception e) {
// e.printStackTrace();
// }
}
}
else {// 是文件夹,递归
fileSearch(f, filename);
}
}
}
}
}
IO流
IO流概述
- I指Input,称为输入流:负责把数据读到内存中去
- 磁盘/网络/… => 程序/内存
- O指Output,称为输出流:负责把数据写出去
- 程序/内存 => 磁盘/网络/…
- I指Input,称为输入流:负责把数据读到内存中去
IO流分类
- 按流的方向分为:输入流/输出流
- 按流的数据最小单位分为:字节流/字符流
- 字节流:适合操作所有类型的文件,比如图片、视频、音频、文本文件的复制、转移等等
- 字符流:只适合操作纯文本文件,比如:读写txt、java文件等
总结IO流分类
- 字节输入流:以内存为基准,来自磁盘文件/网络中的数据已字节的形式读入内存中去的流
- 字节输出流:以内存为基准,将内存中的数据以字节写出到磁盘文件/网络中去的流
- 字符输入流:以内存为基准,来自磁盘文件/网络中的数据以字符的形式读入内存中去的流
- 字符输出流:以内存为基准,将内存中的数据以字符写出到磁盘文件/网络介质中去的流
IO流的体系
字节输入流(FileInputStream)
作用:以内存为基准,把磁盘文件中的数据以字节的形式读入内存中去
构造器 | 说明 |
---|---|
public FileInputStream(File file) | 根据File对象创建字节输入流对象 |
public FileInputStream(String name) | 根据文件路径创建字节输入流对象 |
方法 | 说明 |
---|---|
public int read() | 每次读取一个字节数据,如果已经到达文件末尾,则返回-1 |
public int read(byte[] buffer) | 每次用一个字节数组读取数据,返回字节数组读取了多少字节,如果已经达末尾,则返回-1 |
public byte[] readAllBytes() | 一次性读取整个文件内容,返回字节数组 |
示例代码:
- 每次读取一个字节数据
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// 使用FileInputStream从内存中读取文件,每次读取一个字节
public class FileInputStreamTest1 {
public static void main(String[] args) throws IOException {
// 1. 两种输入流构造方法
// 方式一:
// File file = new File("src/aa.txt"); // 该文件内容为: ab
// FileInputStream is = new FileInputStream(file);
// 方式二:推荐
FileInputStream is = new FileInputStream("src/aa.txt");
// 2. 读取文件内容
// public int read() 每次读取一个字节,文件指针后移一位,没有数据返回-1
// 2.1 不推荐写法,用于了解
// int read1 = is.read();
// System.out.println((char)read1); // a
//
// int read2 = is.read(); // b
// System.out.println((char)read2);
//
// int read3 = is.read(); // -1
// System.out.println(read3);
// 2.2 使用循环改改良2.1
int b; // 用于记录当前读取的字节
while((b = is.read())!= -1){
System.out.print((char) b);
}
/*
在上面2.2的读取性能是很差的,
且读取汉字还会乱码,因为每次只读取一个字节,而汉字是两个字节(gbk)或三个字节(utf-8)
流使用完后必须关闭,释放系统资源
*/
is.close();
}
} - 每次读取多个字节
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// 使用FileInputStream每次读取多个字节
public class FileInputStreamTest2 {
public static void main(String[] args) throws IOException {
// 创建一个字节输入流管道和源文件接通 文件内容为:abc66
FileInputStream is = new FileInputStream("src/bb.txt");
// 创建一个缓存数组
byte [] buffer = new byte[3];
// public int read(byte[] b) 读取多个字节,将字节数组作为参数传入,返回读取的字节数
// 方式1:
int len = is.read(buffer);
System.out.println("第一次读了:"+ len + "个字节"); // 3
System.out.println(new String(buffer)); // abc
// int len2 = is.read(buffer);
// System.out.println("第二次读了:"+ len2 + "个字节"); // 2
// System.out.println(new String(buffer)); // 66c
/*
问题:
因为每次读取到的字节放入缓存字节数组中覆盖上次的内容,
如果最后一处读取的长度小于缓存数组的长度,那么内容无法完全覆盖上次的内容
解决办法:
读多少取多少
new String(byte[] b, int off, int len)
*/
// 优化如下
// 方式二:都多少,取多少
int len2 = is.read(buffer);
System.out.println("第二次读了:"+ len2 + "个字节"); // 2
System.out.println(new String(buffer, 0, len2)); // 66
// 测试:如果文件已经读取完毕,再次读取,返回-1
int len3 = is.read(buffer);
System.out.println(len3);
is.close();
}
}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// 使用FileInputStream每次读取多个字节
public class FileInputStreamTest3 {
public static void main(String[] args) throws IOException {
// 创建一个字节输入流管道和源文件接通 文件内容为:abc66
FileInputStream is = new FileInputStream("src/bb.txt");
// 使用循环读取数据到字节数组中
byte [] buffer = new byte[3];
int len;
while ((len = is.read(buffer))!= -1){
// 每一次读多少取多少
System.out.print(new String(buffer, 0, len));
}
/*
但是该方式仍然无法解决读取汉字乱码问题,无法避免汉字编码被截断的问题
但是适用于文件拷贝操作
*/
/*
解决汉字乱码的关键就是不截断汉字的编码,那就一次性读取整个文件
字节输入流FileInputStream提供了读取全部字节的方法,如下
public byte[] readAllBytes()
但是如果文件太大,创建的字节数组太大,会报内存溢出异常
读写文本更适合使用字符流
*/
// byte[] bytes = is.readAllBytes();
// System.out.println(new String(bytes));
is.close();
}
}
注意:直接把文件数据全部读取到一个字节数组可以避免乱码,但如果文件过大,创建的字节数组也会过大,可能引起内存溢出。读写文本更适合用字符流,字节流适合做数据的转移,如:文件复制等。
字节输出流(FileOutputStream)
作用:以内存为基准,把内存中的数据已字节的形式写出到文件中去
构造器 | 说明 |
---|---|
FileOutputStream(File file) | 创建一个字节输出流,以写入模式打开指定文件 |
FileOutputStream(String filepath) | 创建一个字节输出流,以写入模式打开指定文件 |
FileOutputStream(File file, boolean append) | 创建一个字节输出流,以写入模式打开指定文件,如果第二个参数为true,则追加到文件末尾 |
FileOutputStream(String filepath, boolean append) | 创建一个字节输出流,以写入模式打开指定文件,如果第二个参数为true,则追加到文件末尾 |
方法 | 描述 |
---|---|
public void write(int b) | 写一个字节出去 |
public void write(byte[] b) | 写一个字节数组出去 |
public void write(byte[] b, int off, int len) | 写一个字节数组的一部分出去,从off开始写,长度为len |
public void close() | 关闭流 |
示例代码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// 文件字节输出流,写文件到硬盘
public class FileOutPutStreamTest5 {
public static void main(String[] args) throws IOException {
/*
创建文件字节输出流对象,构造函数中的文件可不存在,会自动创建
覆盖式写入:每次写入,会覆盖源文件的原本内容
*/
// FileOutputStream os = new FileOutputStream("src/out.txt");
/*
追加式写入:每次写入,不会覆盖源文件的原本内容,而是追加到文件末尾
*/
FileOutputStream os = new FileOutputStream("src/out.txt", true);
/*
写入方式一:
写入单个字节,write(int b)
*/
os.write('a');
os.write(98);
//因为汉字不止一个字节,所以会被截断,导致文件中乱码
//os.write('徐');
/*
写入方式二:
一次写入多个字节,write(byte[] b)
*/
byte[] bytes = "aa我爱你中国".getBytes();
os.write(bytes);
/*
写入换行符: \r\n
*/
os.write("\r\n".getBytes());
/*
写入方式三:
指定写入的字节个数 write(byte[] b, int off, int len)
*/
os.write("aa我爱你中国".getBytes(), 2, 9);
os.close();
}
}
复制文件
字节流非常适合做一切文件的复制操作。
任何文件的底层都是字节,字节流做复制,是一字不漏的转移完全部字节,只要复制后的文件格式一致就没问题
1 | // 文件复制 |
资源的释放
创建流对象时,使用try-with-resource语句,自动释放资源。
jdk7开始提供的,更推荐使用1
2
3
4
5
6
7
8
9
10try(定义资源1;定义资源2;...
// 注意:这里只能放置资源对象。(流对象)
// 如何判断?资源都会实现AutoCloseable接口,并实现close方法
// 用完之后会自动调用close方法完成资源释放操作
){
// 可能出现异常的代码逻辑
} catch (异常类名 变量名) {
// 处理异常的代码逻辑
}使用finally语句,手动释放资源。
finally代码区的特点:无论try语句是否出现异常,finally代码区都会执行,除非JVM退出。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21FileInputStream is = null;
FileOutputStream os = null;
try {
// 可能出现异常的代码逻辑
is = new FileInputStream("");
os = new FileOutputStream("");
}catch (IOException e) {
throw new RuntimeException(e);
} finally {
// 5.关闭流,从里往外关,先创建的后关
try {
if(os!=null) os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(is != null) is.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
字符输入流(FileReader)
作用:以内存为基准,可以把文件中的数据以字符的形式读入到内存中去
构造器 | 说明 |
---|---|
FileReader(File file) | 创建一个字符输入流,以读模式打开指定文件 |
FileReader(String filepath) | 创建一个字符输入流,以读模式打开指定文件 |
方法 | 说明 |
---|---|
read() | 每次读取一个字符,如果已经到达文件末尾,则返回 -1 |
read(char[] buffer) | 每次用一个字符数组去读取数据,返回读取到的字符数,没有则返回 -1 |
示例代码: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// 字符输入流一次读取一个或多个字符
public class FileReaderTest1 {
public static void main(String[] args) {
try (
// 1. 创建一个字符输入流对象
FileReader reader = new FileReader("src/出师表.txt");
){
// 2. 一次读取一个字符,性能较差
// int c; // 读取一个字符返回其编码
// while ((c = reader.read()) != -1){
// System.out.print((char)c);
// }
//3. 一次读取多个字符,性能较好
char [] buffer = new char[3]; // 每次读取3个字符
int len;
while ((len = reader.read(buffer)) != -1){
System.out.print(new String(buffer, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符输出流(FileWriter)
作用:以内存为基准,把内存中的数据以字符的形式写出到文件中
构造器 | 功能 |
---|---|
FileWriter(String filepath) | 创建字符输出流,用于将数据写入文件 |
FileWriter(File file) | 创建字符输出流,用于将数据写入文件 |
FileWriter(File file,boolean append) | 创建字符输出流,用于将数据写入文件,可追加 |
FileWriter(String filepath,boolean append) | 创建字符输出流,用于将数据写入文件,可追加 |
方法 | 功能 |
---|---|
write(int c) | 写入一个字符 |
write(String str) | 写入一个字符串 |
write(String str,int off,int len) | 写入一个字符串的指定部分 |
write(char[] cbuf) | 写入一个字符数组 |
write(char[] cbuf,int off,int len) | 写入一个字符数组的指定部分 |
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
25
26
27
28
29
30
31
32
33
34
35
36// 文件字符输出流
public class FileWriteTest2 {
public static void main(String[] args) {
try (
// 0. 创建字符输出流对象
FileWriter writer = new FileWriter("src/字符输出流test.txt");
// 追加模式
// FileWriter writer = new FileWriter("src/字符输出流test.txt",true);
){
// 1. void write(int c) 写入一个字符
writer.write('A');
writer.write(97);
writer.write('徐');
// 2. void write(String str) 写入一个字符串
writer.write("天天向上");
// 3. void write(String str, int off, int len) 写入一个字符串的一部分
writer.write("天天向上", 0, 2);
// 4. void write(char[] cbuf) 写入一个字符数组
char [] chars = {'a', 'b', 'c','你','好'};
writer.write(chars);
// 5. void write(char[] cbuf, int off, int len) 写入一个字符数组的一部分
writer.write(chars, 3, 2);
// 6. 写入换行符 \r\n
writer.write("\r\n");
writer.write("哈哈");
} catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲流(BufferedStream)
缓冲流是对原始流进行包装,以提高原始流读写数据的性能
- 字节缓冲流
- 字节缓存输入流:BufferedInputStream 对应 FileInputStream
- 字节缓存输出流:BufferedOutputStream 对应 FileOutputStream
- 字符缓冲流
- 字符缓存输入流:BufferedReader 对应 FileReader
- 字符缓存输出流:BufferedWriter 对应 FileWriter
字节缓冲输入输出流
原理:字节缓冲输入流自带了8KB缓冲池;字节缓冲输出流也自带了8KB缓冲池
构造器 | 功能 |
---|---|
BufferedInputStream(InputStream is) | 构造方法,参数是字节输入流 |
BufferedOutputStream(OutputStream os) | 构造方法,参数是字节输出流 |
示例: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// 字节输入输出缓冲流
public class FileByteBufferTest {
public static void main(String[] args) {
try (
FileInputStream is = new FileInputStream("src/疯狂星期四.png");
// 1.1 创建字节输入缓存流
BufferedInputStream bis = new BufferedInputStream(is);
FileOutputStream os = new FileOutputStream("src/疯狂星期四copy.png");
//2.2 创建字节输出缓存流
BufferedOutputStream bos = new BufferedOutputStream(os);
){
byte[] buffer = new byte[1024];
int len;
while ((len = bis.read(buffer)) != -1){
bos.write(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符缓冲输入流(BufferedReader)
作用:自带8K(8192)的字符缓冲流,可以提高字符输入流读取字符数据的性能
构造器 | 说明 |
---|---|
BufferedReader(Reader r) | 创建一个使用默认大小输入缓冲区的缓冲字符输入流 |
字符缓冲输入流新增了按行读取字符的方法
方法 | 说明 |
---|---|
String readLine() | 从该流中读取一行数据返回,如果已经到达流的末尾,则返回 null |
示例代码: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// 字符输入输出缓冲流
public class BufferReaderTest {
public static void main(String[] args) {
try (
FileReader reader = new FileReader("src/out.txt");
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(reader);
){
// char[] buffer = new char[1024];
// int len;
// while ((len = br.read(buffer)) != -1){
// System.out.print(new String(buffer, 0, len));
// }
// 字符缓存输入流新方法 readLine()
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符缓冲输出流(BufferedWriter)
作用:自带8K(8192)的字符缓冲流,可以提高字符输出流输出字符数据的性能
构造方法 | 功能 |
---|---|
BufferedWriter(Writer out) | 创建一个使用默认大小8K的缓冲输出流 |
字符输出缓冲流新功能:换行
方法 | 功能 |
---|---|
public void newLine() | 换行,默认为系统换行符 |
示例代码: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// 字符缓冲输出流,写出数据
public class BufferWriterTest {
public static void main(String[] args) {
try(
FileWriter fw = new FileWriter("src/bufferwriter.txt",true);
// 创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(fw);
){
bw.write('a');
bw.write("你好啊");
// 新增的方法:写入换行
bw.newLine();
char [] chr = {'a', 'b', 'c'};
bw.write(chr,2,1);
bw.newLine();
String str = "good time";
bw.write(str,5,4);
}catch (Exception e){
e.printStackTrace();
}
}
}
字符转换流
如果代码编码和被读取的文本文件的编码是一致的,使用字符流读取文本文件时不会出现乱码!
如果代码编码和被读取的文本文件的编码是不一致的,使用字符流读取文本文件时就会出现乱码!
字符输入转换流(InputStreamReader)
- 解决不同编码时,字符流读取文本内容乱码的问题。
- 先获取文件的原始字节流,再将其按真实的字符编码转换成字符输入流,这样字符输入流中的字符就不乱码了。
构造器 | 说明 |
---|---|
InputStreamReader(InputStream is) | 把原始的字节输入流,按照代码默认编码转换成字符输入流 |
InputStreamReader(InputStream is, String charsetName) | 创建一个使用指定字符集的 InputStreamReader |
示例代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// 字符输入转换流
public class InputStreamReaderTest {
public static void main(String[] args) {
try (
// 1. 得到文件的原始字节输入流
FileInputStream frd = new FileInputStream("src/转换流gbk.txt");
// 2. 把原始字节输入流按指定字符集进行转换成字符输入流
InputStreamReader in = new InputStreamReader(frd, "GBK");
// 3. 把字符输入流包装成字符缓冲输入流
BufferedReader br = new BufferedReader(in);
){
String line ;
while ((line = br.readLine())!=null){
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
字符输出流转换流(OutputStreamWriter)
- 作用:可以控制写出去的字符使用什么字符编码
- 获取字节输出流,再按照指定字符编码,将其转换成字符输出流
构造器 | 说明 |
---|---|
OutputStreamWriter(OutputStream os) | 把原始的字节输出流,按照代码默认编码转换成字符输出流 |
OutputStreamWriter(OutputStream os, String charsetName) | 创建一个使用指定字符集的 OutputStreamWriter |
示例代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 字符输出转换流
public class OutputStreamWriterTest {
public static void main(String[] args) {
try(
// 1. 创建一个字节输出流对象
FileOutputStream os = new FileOutputStream("src/transformout.txt");
// 2. 创建一个字符输出转换流对象, 指定字符集GBK
OutputStreamWriter osw = new OutputStreamWriter(os,"GBK");
// 3. 使用字符输出缓冲流对象,写入数据
BufferedWriter bw = new BufferedWriter(osw);
){
bw.write("abc你好hh");
}catch (Exception e){
e.printStackTrace();
}
}
}
打印流(PrintStream/PrintWriter)
作用:打印流可以实现更方便,更高效的打印数据出去,能实现打印啥出去就是啥出去。
PrintStream提供的打印数据的方案
构造器 | 说明 |
---|---|
PrintStream(OutputStream/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
PrintStream(String fileName, Charset charset) | 可以指定写出去的字符编码 |
PrintStream(OutputStream out, boolean autoFlush) | 可以设置自动刷新 |
PrintStream(OutputStream out, boolean autoFlush, String encoding) | 可以设置自动刷新和字符编码 |
方法 | 说明 |
---|---|
println(XXX xx) | 打印任意类型的数据出去 |
public void write(int/byte[]/byte[]一部分) | 可以支持写字节数据出去 |
PrintWriter提供的打印数据的方案
构造器 | 说明 |
---|---|
PrintWriter(OutputStream/Writer/File/String) | 打印流直接通向字节输出流/文件/文件路径 |
PrintWriter(String filename, Charset charset) | 指定写出去的字符编码 |
PrintWriter(OutputStream out/Writer, boolean autoFlush) | 可以设置自动刷新 |
PrintWriter(OutputStream out, boolean autoFlush, String encoding) | 可以设置自动刷新和字符编码 |
方法 | 说明 |
---|---|
public void println(XXX xx) | 打印任意类型的数据出去 |
public void print(int/String/char[]/…) | 打印字符 |
演示代码:https://gitee.com/xu-nuojie/java-io/tree/master/src/main/java/com/xnj/print_stream_writer_demo
区别
- 打印数据的功能上是一模一样的:都是使用方柏霓,性能高效(核心优势)
- PrintStream继承自字节输出流OutputStream,因此支持写字节数据的方法。
- PrintWriter继承自字符输出流Writer,因此支持写字符数据的方法。
应用:输出语句的重定向。
可以把输出语句的打印位置改到某个文件中去。
1 | PrintStream ps = new PrintStream("文件地址"); |
示例代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 打印流,重定向println
public class Test2 {
public static void main(String[] args) {
// 打印到控制台
System.out.println("helloWorld");
try (
PrintStream ps = new PrintStream("src/systemout.txt");
){
System.setOut(ps);
// 打印到文件
System.out.println("helloWorld");
} catch (Exception e) {
e.printStackTrace();
}
}
}
数据流
数据输出流(DataOutputStream)
- 允许把数据和其类型一并写出去
构造器 | 说明 |
---|---|
DataOutputStream(OutputStream out) | 创建新数据输出流包装基础的字节输出流 |
| 方法 | 说明 |
| writeByte(int v) | 将指定的 byte 值写入此数据输出流 |
| writeInt(int v) | 将指定的 int 值写入此数据输出流 |
| writeUTF(String v) | 将字符串数据以UTF-8编码成字节写入此数据输出流 |
| writeBoolean(boolean v) | 将指定的 boolean 值写入此数据输出流 |
| write(int/byte[]/byte[]一部分) | 支持写字节数据出去 |
数据输入流(DataInputStream)
- 用于读取数据输出流写出去的数据
构造器 | 描述 |
---|---|
DataInputStream(InputStream in) | 创建一个数据输入流,以便从指定的输入流读取字节 |
方法 | 描述 |
---|---|
readBoolean() | 从输入流读取一个字节,将其转换为一个 boolean 值并返回 |
readByte() | 从输入流读取一个字节,将其转换为一个 byte 值并返回 |
readChar() | 从输入流读取两个字节,将其转换为一个 char 值并返回 |
readDouble() | 从输入流读取 eight bytes,将其转换为一个 double 值并返回 |
readUTF() | 从输入流读取一个 UTF-8 编码的字符串并返回 |
readInt()/read(byte[] b) | 支持读字节数据进来 |
序列化流
- 对象序列化:把Java对象写入到对象文件中去
- 注意:对象必须实现Serializable接口
- 如果某个属性不想被序列化,那么在属性前加上transient关键字
- 对象反序列化:把文件里的Java对象读出来
对象字节输出流(ObjectOutputStream)
构造器 | 说明 |
---|---|
ObjectOutputStream(OutputStream out) | 创建一个对象字节输出流,向指定的输出流中写入字节 |
方法 | 说明 |
---|---|
void writeObject(Object obj) | 将指定的对象写入字节流 |
如果要一次序列化多个对象:可以用一个ArrayList集合存储多个对象,然后直接对集合进行序列化即可
- ArrayList集合已经实现了序列化接口。
对象字节输入流(ObjectInputStream)
构造器 | 说明 |
---|---|
ObjectInputStream(InputStream in) | 创建一个对象字节输入流,从指定的输入流中读取字节 |
方法 | 说明 |
---|---|
Object readObject() | 把存储在文件中的Java对象读出来 |
IO框架
Commons-io
:可以去了解下,它是apache下的一个开源项目,提供了一些很实用的工具类,
FileUtile类提供的部分方法
- copyFile(String srcFile, String destFile) 复制文件
- copyDirectory(String srcDir, String destDir) 复制文件夹
- deleteDirectory(File directory) 删除文件夹
- readFileToString(File file, String encoding) 读出文件所有数据以字符串的形式返回
- writeStringToFile(File file, String data, String encoding, boolean append) 将字符串写入文件
IOUtils类提供的部分方法
- copy(InputStream input, OutputStream output) 复制文件
- copy(Reader input, Writer output) 复制文件
- write(String data, OutputStream output, String encoding) 将字符串写入文件
Java自己也提供了一些便捷
Files类就提供了一些便捷的方法。