File 文件类

创建文件对象的构造方法:

方法 功能
File(String pathname) 通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例。(其中路径可以是相对路径也可以是绝对路径)
File(File parent, String child) 通过给定的父抽象路径名和子路径名字符串创建一个新的File实例。
File(String parent, String child) 根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。
File(URI uri) 通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例。

文件常用方法:

方法 功能
exists() 判断文件是否存在
isDirectory() 判断是否是文件夹
isFile() 判断是否是文件
length() 获取文件的长度
lastModified() 文件最后修改时间的 long 值,可以配合 Date 类输出直观时间
setLastModified(long time) 设置文件修改时间为 time
renameTo(File dest) 文件重命名
list() 以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
listFiles() 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
getParent() 以字符串形式返回获取所在文件夹
getParentFile() 以文件形式返回获取所在文件夹
mkdir() 创建文件夹,如果父文件夹不存在,创建就无效
mkdirs() 创建文件夹,如果父文件夹不存在,就会创建父文件夹
creatNewFile() 创建一个空文件,如果父文件夹不存在,就会抛出异常。所以在创建一个空文件之前,通常会先创建父目录:filename.getParentFile().mkdirs()
listRoots() 列出所有的盘符 c: d: e: 等等
delete() 删除文件
deleteOnExit() JVM结束的时候,删除文件,常用于临时文件的删除

Stream 流

Java 语言定义了许多类专门负责各种方式的输入或者输出,这些类都被放在 java.io 包中。

流的作用:为了永久性的保存数据。

分类:根据数据流向的不同分为输入流和输出流;根据处理数据类型的不同分为字符流和字节流。其中,所有输入流类都是抽象类 InputStream (字节输入流),或者抽象类 Reader (字符输入流)的子类;而所有输出流都是抽象类 OutputStream (字节输出流)或者 Writer (字符输出流)的子类。

文件字节流

FileInputStream

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 stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class TestStream {
public static void main(String[] args) {
try {
//准备文件lol.txt其中的内容是AB,对应的ASCII分别是65 66
File f =new File("d:/lol.txt");
//创建基于文件的输入流
FileInputStream fis =new FileInputStream(f);
//创建字节数组,其长度就是文件的长度
byte[] all =new byte[(int) f.length()];
//以字节流的形式读取文件所有内容
fis.read(all);
for (byte b : all) {
//打印出来是65 66
System.out.println(b);
}

//每次使用完流,都应该进行关闭
fis.close();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

一些常用方法:

方法 功能
public void close() throws IOException{} 关闭此文件输入流并释放与此流有关的所有系统资源。抛出 IOException 异常。
protected void finalize()throws IOException {} 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出 IOException 异常。
public int read(int r)throws IOException{} 这个方法从 InputStream 对象读取指定字节的数据。返回为整数值。返回下一字节数据,如果已经到结尾则返回 -1。
public int read(byte[] r) throws IOException{} 这个方法从输入流读取 r.length 长度的字节。返回读取的字节数。如果是文件结尾则返回 -1。
public int available() throws IOException{} 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取的字节数。返回一个整数值。

FileOutputStream

OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是 OutputStream 子类,以 FileOutputStream 为例向文件写出数据。(注: 如果文件d:/lol2.txt不存在,写出操作会自动创建该文件。但是如果是文件 d:/xyz/lol2.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
package stream;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

public class TestStream {
public static void main(String[] args) {
try {
// 准备文件lol2.txt其中的内容是空的
File f = new File("d:/lol2.txt");
// 准备长度是2的字节数组,用88,89初始化,其对应的字符分别是X,Y
byte data[] = { 88, 89 };

// 创建基于文件的输出流
FileOutputStream fos = new FileOutputStream(f);
// 把数据写入到输出流
fos.write(data);
// 关闭输出流
fos.close();

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

一些常用方法:

方法 功能
public void close() throws IOException{} 关闭此文件输入流并释放与此流有关的所有系统资源。抛出 IOException 异常。
protected void finalize()throws IOException {} 这个方法清除与该文件的连接。确保在不再引用文件输入流时调用其 close 方法。抛出 IOException 异常。
public void write(int w)throws IOException{} 这个方法把指定的字节写到输出流中。
public void write(byte[] w) 把指定数组中 w.length 长度的字节写到 OutputStream 中。

文件字符流

FileReader

FileReader 是 Reader 子类,该类按字符读取流中数据。可以通过以下几种构造方法创建需要的对象。

  • FileReader(File file)
  • FileReader(FileDescriptor fd)
  • FileReader(String fileName)

以 FileReader 为例进行文件读取:

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
package stream;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class TestStream {
public static void main(String[] args) {
// 准备文件lol.txt其中的内容是AB
File f = new File("d:/lol.txt");
// 创建基于文件的Reader
try (FileReader fr = new FileReader(f)) {
// 创建字符数组,其长度就是文件的长度
char[] all = new char[(int) f.length()];
// 以字符流的形式读取文件所有内容
fr.read(all);
for (char b : all) {
// 打印出来是A B
System.out.println(b);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

一些常用方法:

方法 功能
public int read() throws IOException 读取单个字符,返回一个int型变量代表读取到的字符。
public int read(char [] c, int offset, int len) 读取字符到c数组,返回读取到字符的个数。

FileWriter

FileWriter 是 Writer 的子类,该类按字符向流中写入数据。可以通过以下几种构造方法创建需要的对象。

  • FileWriter(File file)

  • FileWriter(File file, boolean append)

  • FileWriter(FileDescriptor fd)
  • FileWriter(String fileName, boolean append)

append参数:若为 true 则在文件末尾追加,若为 false 覆盖文件内容。

以 FileWriter 为例把字符串写入到文件:

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 stream;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class TestStream {

public static void main(String[] args) {
// 准备文件lol2.txt
File f = new File("d:/lol2.txt");
// 创建基于文件的Writer
try (FileWriter fr = new FileWriter(f)) {
// 以字符流的形式把数据写入到文件中
String data="abcdefg1234567890";
char[] cs = data.toCharArray();
fr.write(cs);

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

一些常用方法:

方法 功能
public void write(int c) throws IOException 写入单个字符c。
public void write(char [] c, int offset, int len) 写入字符数组中开始为offset长度为len的某一部分。
public void write(String s, int offset, int len) 写入字符串中开始为offset长度为len的某一部分。

中文问题

用 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
32
33
34
35
36
package stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class TestStream {
public static void main(String[] args) {
File f = new File("E:\\project\\j2se\\src\\test.txt");
try (FileInputStream fis = new FileInputStream(f);) {
byte[] all = new byte[(int) f.length()];
fis.read(all);

//文件中读出来的数据是
System.out.println("文件中读出来的数据是:");
for (byte b : all)
{
int i = b&0x000000ff; //只取16进制的后两位
System.out.println(Integer.toHexString(i));
}
System.out.println("把这个数字,放在GBK的棋盘上去:");
String str = new String(all,"GBK");
System.out.println(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*Output:
文件中读出来的数据是:
d6
d0
把这个数字,放在GBK的棋盘上去:

*/

用FileReader 字符流正确读取中文

FileReader 得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了。而 FileReader 使用的编码方式是 Charset.defaultCharset() 的返回值,如果是中文的操作系统,就是 GBK。FileReader 是不能手动设置编码方式的,为了使用其他的编码方式,只能使用 InputStreamReader 来代替,像这样:

1
new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"));

以“中”为例子:

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 stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

public class TestStream {

public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
File f = new File("E:\\project\\j2se\\src\\test.txt");
System.out.println("默认编码方式:"+Charset.defaultCharset());
//FileReader得到的是字符,所以一定是已经把字节根据某种编码识别成了字符了
//而FileReader使用的编码方式是Charset.defaultCharset()的返回值,如果是中文的操作系统,就是GBK
try (FileReader fr = new FileReader(f)) {
char[] cs = new char[(int) f.length()];
fr.read(cs);
System.out.printf("FileReader会使用默认的编码方式%s,识别出来的字符是:%n",Charset.defaultCharset());
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//FileReader是不能手动设置编码方式的,为了使用其他的编码方式,只能使用InputStreamReader来代替
//并且使用new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")); 这样的形式
try (InputStreamReader isr = new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8"))) {
char[] cs = new char[(int) f.length()];
isr.read(cs);
System.out.printf("InputStreamReader 指定编码方式UTF-8,识别出来的字符是:%n");
System.out.println(new String(cs));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*Output:
默认编码方式:GBK
FileReader会使用默认的编码方式%s,识别出来的字符是:
(乱码)
InputStreamReader 指定编码方式UTF-8,识别出来的字符是:
?中
*/
  • 解释: 为什么中字前面有一个?
    如果是使用记事本另存为UTF-8的格式,那么在第一个字节有一个标示符,叫做 BOM 用来标志这个文件是用 UTF-8 来编码的。

关闭流的方式

在 try 中关闭

在try的作用域里关闭文件输入流,在前面的示例中都是使用这种方式,这样做有一个弊端;
如果文件不存在,或者读取的时候出现问题而抛出异常,那么就不会执行这一行关闭流的代码,存在巨大的资源占用隐患。 不推荐使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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:/lol.txt");
FileInputStream fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
// 在try 里关闭流
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

在 finally 中关闭

这是标准的关闭流的方式:

  1. 首先把流的引用声明在 try 的外面,如果声明在 try 里面,其作用域无法抵达 finally。
  2. 在 finally 关闭之前,要先判断该引用是否为空。
  3. 关闭的时候,需要再一次进行 try catch 处理。

这是标准的严谨的关闭流的方式,但是看上去很繁琐,所以写不重要的或者测试代码的时候,都会采用上面的有隐患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
26
27
28
29
30
31
package stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class TestStream {
public static void main(String[] args) {
File f = new File("d:/lol.txt");
FileInputStream fis = null;
try {
fis = new FileInputStream(f);
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 在finally 里关闭流
if (null != fis)
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

使用 try() 的方式

把流定义在 try() 里, try, catch 或者 finally 结束的时候,会自动关闭。这种编写代码的方式叫做 try-with-resources, 这是从 JDK7 开始支持的技术。所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在 try() 中进行实例化。 并且在try, catch, finally 结束的时候自动关闭,回收相关资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class TestStream {
public static void main(String[] args) {
File f = new File("d:/lol.txt");

//把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
try (FileInputStream fis = new FileInputStream(f)) {
byte[] all = new byte[(int) f.length()];
fis.read(all);
for (byte b : all) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

缓存流

以介质是硬盘为例,字节流和字符流的弊端:
在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。

为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。

缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了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
26
27
28
29
30
31
32
33
34
package stream;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class TestStream {
public static void main(String[] args) {
// 准备文件lol.txt其中的内容是
// garen kill teemo
// teemo revive after 1 minutes
// teemo try to garen, but killed again
File f = new File("d:/lol.txt");
// 创建文件字符流
// 缓存流必须建立在一个存在的流的基础上
try (
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr);
)
{
while (true) {
// 一次读一行
String line = br.readLine();
if (null == line)
break;
System.out.println(line);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

使用缓存流写出数据

PrintWriter 缓存字符输出流, 可以一次写出一行数据:

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
package stream;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class TestStream {
public static void main(String[] args) {
// 向文件lol2.txt中写入三行语句
File f = new File("d:/lol2.txt");

try (
// 创建文件字符流
FileWriter fw = new FileWriter(f);
// 缓存流必须建立在一个存在的流的基础上
PrintWriter pw = new PrintWriter(fw);
) {
pw.println("garen kill teemo");
pw.println("teemo revive after 1 minutes");
pw.println("teemo try to garen, but killed again");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

flush

有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到 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
package stream;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TestStream {
public static void main(String[] args) {
//向文件lol2.txt中写入三行语句
File f =new File("d:/lol2.txt");
//创建文件字符流
//缓存流必须建立在一个存在的流的基础上
try(FileWriter fr = new FileWriter(f);PrintWriter pw = new PrintWriter(fr);) {
pw.println("garen kill teemo");
//强制把缓存中的数据写入硬盘,无论缓存是否已满
pw.flush();
pw.println("teemo revive after 1 minutes");
pw.flush();
pw.println("teemo try to garen, but killed again");
pw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

数据流

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
48
49
50
51
52
53
54
55
package stream;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class TestStream {

public static void main(String[] args) {
write();
read();
}

private static void read() {
File f =new File("d:/lol.txt");
try (
FileInputStream fis = new FileInputStream(f);
DataInputStream dis =new DataInputStream(fis);
){
boolean b= dis.readBoolean();
int i = dis.readInt();
String str = dis.readUTF();

System.out.println("读取到布尔值:"+b);
System.out.println("读取到整数:"+i);
System.out.println("读取到字符串:"+str);

} catch (IOException e) {
e.printStackTrace();
}

}

private static void write() {
File f =new File("d:/lol.txt");
try (
FileOutputStream fos = new FileOutputStream(f);
DataOutputStream dos =new DataOutputStream(fos);
){
dos.writeBoolean(true);
dos.writeInt(300);
dos.writeUTF("123 this is gareen");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*Output:
读取到布尔值:true
读取到整数:300
读取到字符串:123 this is gareen
*/

对象流

对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘。

一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现 Serializable 接口。

序列化一个对象

创建一个 Hero 对象,设置其名称为 garen。把该对象序列化到一个文件 garen.lol。然后再通过序列化把该文件转换为一个 Hero 对象。

注:把一个对象序列化有一个前提是:这个对象的类,必须实现了 Serializable 接口。

TestStream.java

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
package stream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import charactor.Hero;

public class TestStream {

public static void main(String[] args) {
//创建一个Hero garen
//要把Hero对象直接保存在文件上,务必让Hero类实现Serializable接口
Hero h = new Hero();
h.name = "garen";
h.hp = 616;

//准备一个文件用于保存该对象
File f =new File("d:/garen.lol");

try(
//创建对象输出流
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream oos =new ObjectOutputStream(fos);
//创建对象输入流
FileInputStream fis = new FileInputStream(f);
ObjectInputStream ois =new ObjectInputStream(fis);
) {
oos.writeObject(h);
Hero h2 = (Hero) ois.readObject();
System.out.println(h2.name);
System.out.println(h2.hp);

} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Hero.java

1
2
3
4
5
6
7
8
9
10
11
package charactor;

import java.io.Serializable;

public class Hero implements Serializable {
//表示这个类当前的版本,如果有了变化,比如新设计了属性,就应该修改这个版本号
private static final long serialVersionUID = 1L;
public String name;
public float hp;

}

System.in/out

System.out 是常用的在控制台输出数据的
System.in 可以从控制台输入数据

System.in

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package stream;

import java.io.IOException;
import java.io.InputStream;

public class TestStream {

public static void main(String[] args) {
// 控制台输入
try (InputStream is = System.in;) {
while (true) {
// 敲入a,然后敲回车可以看到
// 97 13 10
// 97是a的ASCII码
// 13 10分别对应回车换行
int i = is.read();
System.out.println(i);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

Scanner读取字符串

使用 System.in.read 虽然可以读取数据,但是很不方便。使用 Scanner 就可以逐行读取了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package stream;

import java.util.Scanner;

public class TestStream {

public static void main(String[] args) {

Scanner s = new Scanner(System.in);

while(true){
String line = s.nextLine();
System.out.println(line);
}
}
}

Scanner从控制台读取整数

java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入。

使用Scanner从控制台读取整数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package stream;

import java.util.Scanner;

public class TestStream {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int a = s.nextInt();
System.out.println("第一个整数:"+a);
int b = s.nextInt();
System.out.println("第二个整数:"+b);
}
}
/*Output:
123
第一个整数:123
456
第二个整数:456
*/

一些补充

上述常用流关系图

flush() 和 close() 的区别

  • flush()方法

    用来刷新缓冲区的,刷新后可以再次写出。字节缓冲流内置缓冲区,如果没有读取出来,可以使用 flush() 刷新来。

  • close()方法

    用来关闭流释放资源的的,如果是带缓冲区的流对象的 close() 方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出。

什么情况下使用字符流?

  • 字符流也可以拷贝文本文件,但不推荐使用。 因为读取时会把字节转为字符,写出时还要把字符转回字节。

  • 程序需要读取一段文本,或者需要写出一段文本的时候可以使用字符流。

  • 读取的时候是按照字符的大小读取的,不会出现半个中文。

  • 写出的时候可以直接将字符串写出,不用转换为字节数组。