File类的使用
File类的理解
- File类的一个对象,代表一个文件或者一个文件目录(文件夹)。
- File类声明在java.io包下。
- File类中涉及到关于文件或者文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或者写入文件内容,则必须使用IO流来实现。
- 后续File类的对象常会作为参数传递到流的构造器中,指明读取或者写入的“终点“。
File的实例化
File类的创建构造器
1
2
3
|
File(String filePath)
File(String parentPath, String childPath)
File(File parentFile, String childPath)
|

路径的分类
-
相对路径:相较于某个路径下,指明的路径
IDEA中:
在单元测试方法中,默认根目录是当前Module;
在mian方法中,默认根目录是当前Project;
Eclipse中:
无论是单元测试还是main(),相对路径都是基于当前Project的。
-
绝对路径:包括盘符在内的文件或者文件目录的路径
路径分隔符
在Java中,File类提供了一个常量来根据操作系统,动态的提供分隔符:
1
|
public static final String separator;
|
File类的常用方法
File类的获取功能
1
2
3
4
5
6
7
8
9
|
- public String getAbsolutePath():获取绝对路径
- public String getPath():获取路径
- public String getName():获取名称
- public String getParent():获取上层文件目录路径。若无,返回null
- public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
- public long lastModified() :获取最后一次的修改时间,毫秒值
- public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
- public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
|
File类的重命名功能
1
|
- public boolean renameTo(File dest):把文件重命名为指定的文件路径
|
注意:dest文件不能存在。
File类的判断功能
1
2
3
4
5
6
|
- public boolean isDirectory():判断是否是文件目录
- public boolean isFile() :判断是否是文件
- public boolean exists() :判断是否存在
- public boolean canRead() :判断是否可读
- public boolean canWrite() :判断是否可写
- public boolean isHidden() :判断是否隐藏
|
File类的创建功能
1
2
3
|
- public boolean createNewFile() :创建文件。若文件存在,则不创建,返回false
- public boolean mkdir() :创建文件目录。如果此文件目录存在,就不创建了。 如果此文件目录的上层目录不存在,也不创建。
- public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建
|
File类的删除功能
1
|
- public boolean delete():删除文件或者文件夹
|
Java中的删除不走回收站♻️。
要删除一个文件夹,要注意该文件夹内不能包含内容,必须是一个空的文件夹。
IO流概述
流的分类
- 操作数据单位:字节流、字符流
- 数据的流向:输入流、输出流
- 流的角色:节点流(或者叫文件流)、处理流

流的体系结构

红色框的部分为IO流的四个最基本的抽象基类。
蓝色框的部分为需要重点掌握的几个流。
重点说明的几个流结构
| 抽象基类 |
节点流(或文件流) |
缓冲流(处理流的一种) |
| InputStream |
FileInputStream【read(byte[] buffer)】 |
BufferedInputStream |
| OutputStream |
FileOutputStream【write(byte[] buffer,0,len)】 |
BufferedOutputStream |
| Reader |
FileReader【read(char[] cbuf)】 |
BufferedReader【readLine()】 |
| Writer |
FileWriter【writer(char[] cbuf,0,len)】 |
BufferedWriter |
输入、输出的标准化过程
输入过程
- 创建File类的对象,指明读取的数据的来源。(要求此文件一定要存在)
- 创建相应的输入流,将File类的对象作为参数,传入流的构造器中。
- 具体的读入过程:创建对应的byte[]或者char[]。
- 关闭流资源。
说明:程序中出现的异常需要使用try-catch-finally处理。
输出过程
- 创建File类的对象,指明写出的数据的来源。(不要求此文件一定要存在)
- 创建相应的输出流,将File类的对象作为参数,传入流的构造器中。
- 具体的写出过程:write(char[]/byte[],0,len);
- 关闭流资源。
说明:程序中出现的异常需要使用try-catch-finally处理。
节点流(或文件流)
FileReader/FileWriter的使用
FileReader
将硬盘中的文件读入到内存中。
- read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
- 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally来处理。
- 读入的文件一定要存在,否则就会报FileNotFoundException。
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
|
@Test
void testFileReader1() {
FileReader fr = null;
// try-catch快捷键:option+cmd+t
try {
// 1. 创建file对象
File file = new File("hello.txt");
// 2. 创建节点流
fr = new FileReader(file);
// 3. 读取文件流
// 方式一:一个字符一个字符读取
//int data;
//while ((data = fr.read()) != -1) {
// System.out.print((char) data);
//}
// 方式二:一次型读取多个字符
char[] cbuf = new char[5];
int len;
while ((len = fr.read(cbuf)) != -1) {
String output = new String(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.关闭文件流
try {
// 记得添加if判断其是否为null
if (fr != null) {
fr.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
|
FileWriter
从内存中写出数据到硬盘的文件里。
- 输出操作,对应的File可以不存在的。并不会报异常。
- File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
- File对应的硬盘中的文件如果存在:
- 如果流使用的构造器是:FileWriter(file, false) / FileWriter(file) 对原文件的覆盖
- 如果流使用的构造器是:FileWriter(file, 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
|
@Test
void testFileWriter() {
// 1. 创建File对象
File file = new File("hello1.txt");
FileWriter fw = null;
try {
// FileWriter构造器分类:
// 1. 覆盖写入:FileWriter(file) / FileWriter(file,false)
// 2. 追加写入:FileWriter(file, true)
//fw = new FileWriter(file);
// 2. 提供FileWriter的对象,用于数据的写入
fw = new FileWriter(file, true);
// 3.写出的操作
fw.write("hello world!\n");
fw.write("nice to meet you.");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// 4.流资源的关闭
if (fw != null) {
fw.close();
}
} 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
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
/**
* 文本文件的读写
*/
@Test
void testFileReaderAndWriter() {
FileReader fr = null;
FileWriter fw = null;
try {
//1. 创建File类的对象,指明读入和写出的文件
// 注意:不能使用字符流来处理图片等子节数据
File srcFile = new File("hello1.txt");
File desFile = new File("hello2.txt");
//2. 创建输入流和输出流的对象
fr = new FileReader(srcFile);
fw = new FileWriter(desFile);
//3. 数据的读入和写出操作
char[] cbuf = new char[5];
// 记录每次读入到cbuf数组中的字符的个数
int len;
while ((len = fr.read(cbuf)) != -1) {
// 每次写出len个字符
fw.write(cbuf, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4. 关闭流资源
if (fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
- 对于文本文件(.txt, .java, .c, .cpp)等使用字符流处理
- 对于非文本文件(.jpg, .mp3, .mp4, .avi, .doc, .ppt, …)等,使用字节流处理
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
|
@Test
void testInputStreamReaderAndWriter() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 1. 创建输入和输出的文件File对象
File srcImg = new File("input.png");
File desImg = new File("out.png");
// 2.创建输入流和输出流对象
fis = new FileInputStream(srcImg);
fos = new FileOutputStream(desImg);
// 3.开始复制操作,一般使用1024个字节数组
byte[] bytes = new byte[1024];
// 记录每次读到bytes数组中字节的长度
int len;
while ((len = fis.read(bytes)) != -1) {
// 每次写入len个字节
fos.write(bytes, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4.流资源的关闭
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
缓冲流的作用
缓冲流涉及到的类
- BufferedInputStream
- BufferedOutputStream
- BufferedReader
- BufferedWriter
作用
提高流的读写速度。
提高读写速度的原因:内部提供了一个缓冲区。默认情况下是8kb。

典型代码
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
|
/*
实现非文本文件的复制
*/
@Test
public void BufferedStreamTest() throws FileNotFoundException {
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.造文件
File srcFile = new File("爱情与友情.jpg");
File destFile = new File("爱情与友情3.jpg");
//2.造流
//2.1 造节点流
FileInputStream fis = new FileInputStream((srcFile));
FileOutputStream fos = new FileOutputStream(destFile);
//2.2 造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节:读取、写入
byte[] buffer = new byte[10];
int len;
while((len = bis.read(buffer)) != -1){
bos.write(buffer,0,len);
//bos.flush();//刷新缓冲区
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis != null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//说明:关闭外层流的同时,内层流也会自动的进行关闭。关于内层流的关闭,我们可以省略.
// fos.close();
// fis.close();
}
}
|
使用BufferedReader和BufferedWriter处理文本文件
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
56
|
/*
使用BufferedReader和BufferedWriter实现文本文件的复制
*/
@Test
public void testBufferedReaderBufferedWriter(){
BufferedReader br = null;
BufferedWriter bw = null;
try {
//创建文件和相应的流
br = new BufferedReader(new FileReader(new File("dbcp.txt")));
bw = new BufferedWriter(new FileWriter(new File("dbcp1.txt")));
//读写操作
//方式一:使用char[]数组
// char[] cbuf = new char[1024];
// int len;
// while((len = br.read(cbuf)) != -1){
// bw.write(cbuf,0,len);
// // bw.flush();
// }
//方式二:使用String
String data;
while((data = br.readLine()) != null){
//方法一:
// bw.write(data + "\n");//data中不包含换行符
//方法二:
bw.write(data);//data中不包含换行符
bw.newLine();//提供换行的操作
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭资源
if(bw != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(br != null){
try {
br.close();
} 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
|
/*
此时处理异常的话,仍然应该使用try-catch-finally
InputStreamReader的使用,实现字节的输入流到字符的输入流的转换
*/
@Test
public void test1() throws IOException {
FileInputStream fis = new FileInputStream("dbcp.txt");
// InputStreamReader isr = new InputStreamReader(fis);//使用系统默认的字符集
//参数2指明了字符集,具体使用哪个字符集,取决于文件dbcp.txt保存时使用的字符集
InputStreamReader isr = new InputStreamReader(fis,"UTF-8");
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
String str = new String(cbuf,0,len);
System.out.print(str);
}
isr.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
|
/*
此时处理异常的话,仍然应该使用try-catch-finally
综合使用InputStreamReader和OutputStreamWriter
*/
@Test
public void test2() throws Exception {
//1.造文件、造流
File file1 = new File("dbcp.txt");
File file2 = new File("dbcp_gbk.txt");
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
InputStreamReader isr = new InputStreamReader(fis,"utf-8");
OutputStreamWriter osw = new OutputStreamWriter(fos,"gbk");
//2.读写过程
char[] cbuf = new char[20];
int len;
while((len = isr.read(cbuf)) != -1){
osw.write(cbuf,0,len);
}
//3.关闭资源
isr.close();
osw.close();
}
|
说明
文件编码的方式(比如说是GBK),决定了解析时使用的字符集(也只能是GBK)。
1
2
|
FileInputStream fis = new FileInputStream("bgk_file.txt");
InputStreamReader isr = new InputStreamReader(fis,"GBK");
|
补充:编码表
常见的编码表:
-
ASCII:美国标准信息交换码。用一个字节的7位可以表示。
-
ISO8859-1:拉丁码表。欧洲码表。用一个字节的8位表示。
-
GB2312:中国的中文编码表。最多两个字节编码所有字符
-
GBK:中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
-
Unicode:国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的 字符码。所有的文字都用两个字节来表示。
-
UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
客户端/浏览器端。<—–>后台(java,go,php…)<—–>数据库
要求前前后后使用的字符集都要统一:UTF-8
其他的流的使用
标准的输入流输出流
修改默认的输入和输出的行为:
System类的setIn(InputStream is) / setOut(PrintStream ps)方式重新指定输入和输出的流。
打印流
PrintStream 和PrintWriter
二者都是输出流
- 提供了一系列重载的print()和println()方法,用于多种数据类型的输出
- System.out返回的是PrintStream的实例
数据流
DataInputStream 和 DataOutputStream
对象流的使用
对象流
ObjectInputStream 和ObjectOutputStream
作用
对象的序列化机制
序列化过程:对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从 而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传 输到另一个网络节点。
反序列化过程:当其它程序获取了这种二进制流,就可以恢复成原 来的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
46
47
48
49
|
// 序列化过程:
@Test
void testObjectOutputStream() {
ObjectOutputStream oss = null;
try {
FileOutputStream fos = new FileOutputStream("object.serial");
oss = new ObjectOutputStream(fos);
// 将对象序列化
oss.writeObject(new String("hello world!"));
oss.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oss != null) {
try {
oss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 反序列化过程:
@Test
void testObjectInputStream() {
ObjectInputStream ois = null;
try {
FileInputStream fis = new FileInputStream("object.serial");
ois = new ObjectInputStream(fis);
// 反序列化过程
Object object = ois.readObject();
String str = (String) object;
System.out.println("str = " + str);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
|
RandomAccessFile的使用
随机存取文件流使用说明
-
RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
-
RandomAccessFile既可以作为一个输入流,又可以作为一个输出流
-
如果RandomAccessFile作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建。如果写出到的文件存在,则会对原有文件内容进行覆盖。(默认情况下,从头覆盖)
-
可以通过相关的操作,实现RandomAccessFile“插入”数据的效果
典型代码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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
@Test
public void test1() {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
//1.
raf1 = new RandomAccessFile(new File("爱情与友情.jpg"),"r");
raf2 = new RandomAccessFile(new File("爱情与友情1.jpg"),"rw");
//2.
byte[] buffer = new byte[1024];
int len;
while((len = raf1.read(buffer)) != -1){
raf2.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.
if(raf1 != null){
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(raf2 != null){
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void test2() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
raf1.write("xyz".getBytes());//
raf1.close();
}
|
典型代码2
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
|
/*
使用RandomAccessFile实现数据的插入效果
*/
@Test
public void test3() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("hello.txt","rw");
raf1.seek(3);//将指针调到角标为3的位置
//保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int) new File("hello.txt").length());
byte[] buffer = new byte[20];
int len;
while((len = raf1.read(buffer)) != -1){
builder.append(new String(buffer,0,len)) ;
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
raf1.close();
//思考:将StringBuilder替换为ByteArrayOutputStream
}
|
Path、Paths、Files的使用
NIO的使用说明
Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新 的IO API,可以替代标准的Java IO API。
NIO与原来的IO有同样的作用和目 的,但是使用的方式完全不同,NIO支持面向缓冲区的(IO是面向流的)、基于 通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。
Path的使用–jdk7提供
Path的说明
Path替换原有的File类。
如何实例化
Paths 类提供的静态 get() 方法用来获取 Path 对象:
-
static Path get(String first, String … more) : 用于将多个字符串串连成路径
-
static Path get(URI uri): 返回指定uri对应的Path路径
常用方法
1
2
3
4
5
6
7
8
9
10
11
12
|
- String toString() : 返回调用 Path 对象的字符串表示形式
- boolean startsWith(String path) : 判断是否以 path 路径开始
- boolean endsWith(String path) : 判断是否以 path 路径结束
- boolean isAbsolute() : 判断是否是绝对路径
- Path getParent() :返回Path对象包含整个路径,不包含 Path 对象指定的文件路径
- Path getRoot() :返回调用 Path 对象的根路径
- Path getFileName() : 返回与调用 Path 对象关联的文件名
- int getNameCount() : 返回Path 根目录后面元素的数量
- Path getName(int idx) : 返回指定索引位置 idx 的路径名称
- Path toAbsolutePath() : 作为绝对路径返回调用 Path 对象
- Path resolve(Path p) :合并两个路径,返回合并后的路径对应的Path对象
- File toFile(): 将Path转化为File类的对象
|
Files工具类—jdk7提供
作用
操作文件或文件目录的工具类。
常用方法

