15.文件

15.1 File概述

我们知道,程序运行过程的数据都是临时存放在内存中,程序运行完成后,数据将会从内存从清除。

如果想要持久化存储程序运行数据,可以将这些数据持久化到文件中,为了达到该目的,就需要通过

java中的相关类来完成文件相关的操作。

java.io.File类是文件和目录的抽象表示形式。java把磁盘上的文件或目录封装为一个File类,我们可

以通过File类对文件可文件夹进行操作。

File类可以完成如下功能

  1. 创建目录/文件
  2. 删除目录/文件
  3. 获取目录/文件
  4. 判断目录/文件是否存在
  5. 获取文件大小
  6. 目录遍历

代码演示说明

1
2
3
4
5
6
7
8
9
public class FileTest {

public static void main(String[] args) {
//创建一个File类对象,指向磁盘上的某个文件
File file = new File("/Users/peidonggao/Desktop/max.sql");
//获取文件名
System.out.println("fileName: " + file.getName());
}
}

输出结果

1
fileName: max.sql

15.2 File类的构造方法

  • File(File parent, String child) 根据父路径与子路径获取文件或目录,父路径为File类,子路径为字符串
  • File(File parent, String child) 根据给定的文件路径获取文件或目录
  • File(File parent, String child) 根据父路径与子路径获取文件或目录,父路径、子路径都为字符串
  • File(URI uri) 根据网络url获取文件

代码演示说明

File(File parent, String child)

1
2
3
4
5
6
7
8
public class FileConstructorTest {

public static void main(String[] args) {
File file = new File("/Users/peidonggao/Desktop", "crypto-js-3.1.9-1");
//获取文件名
System.out.println("fileName: " + file.getName());
}
}

File(URI uri)

1
2
3
4
5
6
7
8
9
public class FileConstructorTest {

public static void main(String[] args) throws URISyntaxException {
File file = new File(new URI("file:///Users/peidonggao/Desktop/max.sql"));
//获取文件名
System.out.println("fileName: " + file.getName());

}
}

15.3 File类的静态成员变量

  • public static String pathSeparator 当前系统环境变量路径配置分隔符,返回值为字符串
  • public static char pathSeparatorChar 当前系统环境变量路径配置分隔符,返回值为char
  • public static char separatorChar 当前系统文件路径分隔符,返回只为char
  • public static String separator 当前系统文件路径分隔符,返回只为字符串

代码演示说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FileSeparatorTest {

public static void main(String[] args) {
//指定文件路径
String filePath = File.separator + "Users"
+ File.separator + "peidonggao"
+ File.separator + "Desktop"
+ File.separator + "max.sql";
//创建一个File类对象,指向磁盘上的某个文件
File file = new File(filePath);
//获取文件名
System.out.println("fileName: " + file.getName());

}
}

15.4 文件信息获取

  • public String getAbsolutePath() 获取文件的绝对路径字符串
  • public String getName() 获取文件名称
  • public String length() 获取文件的长度

15.5 文件属性判断

  • public boolean exists() 判断文件是否存在
  • public boolean isFile() 判断文件是否一个标准文件
  • public boolean isDirectory() 判断文件是否是一个目录

15.6 文件创建与删除

  • public boolean createNewFile() 当且仅当该名称的文件不存在时,创建一个新的空文件
  • public boolean mkdir() 创建一级目录
  • public boolean mkdirs() 创建多级目录
  • public boolean delete() 删除文件或目录

15.7 文件目录遍历

  • public String[] list() 返回一个字符串数组,表示该目录中的所有子文件和目录
  • public File[] listFiles() 返回一个File数组,表示该目录中的所有子文件和目录

代码演示说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FileListTest {

public static void main(String[] args) {
File file = new File("/Users/peidonggao/Desktop");
String[] files = file.list();
for(String f : files) {
System.out.println(f);
}

File[] listFiles = file.listFiles();
for(File fi : listFiles) {
System.out.println(fi.getName());
}
}
}

15.8 文件过滤器

  • public File[] listFiles(FileFilter filter) 使用FileFilter进行文件过滤
  • public File[] listFiles(FilenameFilter filter) 使用FilenameFilter进行文件过滤

代码演示说明

FileFilter

1
2
3
4
5
6
7
public class MyFileFilter implements FileFilter {
@Override
public boolean accept(File pathname) {
//过滤以.txt结尾的文件
return pathname.getName().toLowerCase().endsWith(".txt");
}
}

编写测试类

1
2
3
4
5
6
7
8
9
10
public class MyFileFilterTest {

public static void main(String[] args) {
File file = new File("/Users/peidonggao/Desktop");
File[] files = file.listFiles(new MyFileFilter());
for(File f : files) {
System.out.println("fileName: " + f.getName());
}
}
}

FilenameFilter

1
2
3
4
5
6
public class MyFilenameFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).getName().toLowerCase().endsWith(".txt");
}
}

编写测试类

1
2
3
4
5
6
7
8
9
10
public class MyFilenameFilterTest {

public static void main(String[] args) {
File file = new File("/Users/peidonggao/Desktop");
File[] files = file.listFiles(new MyFilenameFilter());
for(File f : files) {
System.out.println("fileName: " + f.getName());
}
}
}

16.I/O流

16.1 IO概述

前面我们提到过,我们可以将程序运行过程中的数据,持久保存到磁盘文件中,那么这个数据写入写出到文件的过程,就需要通过Java中的IO技术来实现。

根据数据的流向,可以分为输入流输出流

  • 输入流:把数据从其他设备读取到内存中的流
  • 输出流:把数据从内存中写出到其他设备的流

根据数据的分类,可以分为字节流字符流

IO流顶级父类

输入流 输出流
字节流 InputStream OutputStream
字符流 Reader Writer

16.2 字节输出流

OutputStream为抽象类。是表示输出字节流的所有类的超类

OutputStream常用方法

  • public void close() 关闭此输出流并释放与此流有关的所有系统资源
  • public void flush() 刷新此输出流并强制写出所有缓冲的输出字节
  • public void write(byte[] b)b.length 个字节从指定的 byte 数组写入此输出流
  • public void write(byte[] b, int off, int len)b.length 个字节从指定的 byte 数组写入此输出流

常用子类

  • FileOutputStream 文件输出流,用于将数据写入 File 的输出流

代码演示说明

1
2
3
4
5
6
7
8
9
10
11
12
public class OutputstreamTest {

public static void main(String[] args) throws Exception {
FileOutputStream outputStream = new FileOutputStream("test.txt");
//数据写出到文件
outputStream.write(97);
outputStream.write(93);
//关闭输出流
outputStream.close();

}
}

16.3 字节输入流

InputStream为抽象类。是表示输入字节流的所有类的超类

InputStream常用方法

  • public void close() 关闭此输出流并释放与此流有关的所有系统资源
  • public abstract int read() 输入流中读取数据的下一个字节
  • public int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b
  • public int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组

常用子类

  • FileInputStream 文件输入流,用于从文件系统中的某个文件中获得输入字节

代码演示说明

1
2
3
4
5
6
7
8
9
10
11
12
public class InputStreamTest {

public static void main(String[] args) throws Exception {
FileInputStream inputStream = new FileInputStream("test.txt");
int value = 0;
while((value = inputStream.read()) != -1) {
System.out.println("byte: " + value);
}

inputStream.close();
}
}

字节流读取中文乱码问题

当读取的文本中,包含中文时,在某些情况下,可能会出现中文乱码

已知

  • GBK编码下,一个中文=2个字节
  • UTF-8编码下,一个中文=3个字节

代码演示说明

1
2
3
4
5
6
7
8
9
10
11
12
13
public class InputStreamTest {

public static void main(String[] args) throws Exception {
FileInputStream inputStream = new FileInputStream("test.txt");
byte[] buffer = new byte[2];
int value = 0;
while((value = inputStream.read(buffer, 0, buffer.length)) != -1) {
System.out.println(new String(buffer, "utf-8"));
}

inputStream.close();
}
}

16.4 字符输入流

为了解决字节流读取中文乱码的问题,java中通过字符流来解决该问题,字节流读取的单位是字节,字符流读取的单位是字符

Reader是用于读取字符流的抽象类

Reader常用方法

  • public abstract void close() 关闭该流并释放与之关联的所有资源
  • public int read() 读取单个字符
  • public int read(char[] cbuf) 将字符读入数组
  • public abstract int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分

常用子类

  • FileReader 用来读取字符文件的字符流

代码演示说明

1
2
3
4
5
6
7
8
9
10
public class FileReaderTest {

public static void main(String[] args) throws Exception {
FileReader fileReader = new FileReader("test.txt");
int value = 0;
while((value = fileReader.read()) != -1) {
System.out.println((char)value);
}
}
}

16.5 字符输出流

Writer是用于写入字符流的抽象类

Writer常用方法

  • public abstract void close() 关闭此流,但要先刷新它
  • public void write(String str) 写入字符串
  • public abstract int write(char[] cbuf, int off, int len) 写入字符数组的某一部分

常用子类

  • FileWriter 用来写入字符文件的字符流

代码演示说明

1
2
3
4
5
6
7
8
9
10
11
12
public class FileWriterTest {

public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("test.txt", true);
//append()
fw.write('a');
fw.write('b');
fw.write('c');

fw.close();
}
}

16.6 缓冲流

缓冲流又叫高效流,是对基本操作流的增强,按照数据分类分为

  • 字节缓冲流BufferedInputStreamBufferedOutputStream
  • 字符缓冲流BufferedReaderBufferedWriter

字节缓冲流

构造方法

  • BufferedInputStream(InputStream in) 创建一个新的缓冲输入流
  • BufferedOutStream(OutStream out) 创建一个新的缓冲输出流

代码演示说明

BufferedInputStream

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class BufferedInputStreamTest {

public static void main(String[] args) throws Exception {
FileInputStream in = new FileInputStream("eshop.sql");
BufferedInputStream bis = new BufferedInputStream(in);
byte[] buffer = new byte[2048];
int length = 0;
while((length = bis.read(buffer, 0, buffer.length)) != -1) {
System.out.println(new String(buffer, 0, length));
}

bis.close();
in.close();

}
}

BufferedOutStream

1
2
3
4
5
6
7
8
9
10
public class BufferedOutStreamTest {

public static void main(String[] args) throws Exception {
FileOutputStream out = new FileOutputStream("test.txt");
BufferedOutputStream bos = new BufferedOutputStream(out);
bos.write("hello java".getBytes());
bos.close();
out.close();
}
}

字符缓冲流

  • BufferedReader(Reader in) 创建一个使用默认大小输入缓冲区的缓冲字符输入流
  • BufferedWriter(Writer out) 创建一个使用默认大小输出缓冲区的缓冲字符输出流

代码演示说明

BufferedReader

1
2
3
4
5
6
7
8
9
10
11
12
public class BrTest {

public static void main(String[] args) throws Exception {
FileReader reader = new FileReader("test.txt");
BufferedReader br = new BufferedReader(reader);
char[] buffer = new char[1024];
int len = 0;
while ((len = br.read(buffer, 0, buffer.length)) != -1) {
System.out.println(String.valueOf(buffer, 0, len));
}
}
}

BufferedWriter

1
2
3
4
5
6
7
8
9
public class BwTest {

public static void main(String[] args) throws Exception {
FileWriter fw = new FileWriter("test");
BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello buffer");
bw.close();
}
}

16.7 转换流

在有些时候,读取的文件字符编码与程序所在环境的字符编码不同,这将导致读取到内存中的内容出现乱码。

因此,转换流可以在操作文件的同时进行字符编码的转换

转换流分类

  • InputStreamReader 字节流通向字符流的桥梁,它使用指定的charset读取字节并将其解码为字符
  • OutputStreamWriter 字节流通向字符流的桥梁,可使用指定的charset将要写入流中的字符编码成字节

代码演示说明

InputStreamReader

1
2
3
4
5
6
7
8
9
10
11
12
13
public class InputStreamReaderTest {

public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("test.txt");
//转换流
InputStreamReader in = new InputStreamReader(fis, "utf-8");
char[] buffer = new char[1024];
int len = 0;
while ((len = in.read(buffer, 0, buffer.length)) != -1) {
System.out.println(String.valueOf(buffer, 0, len));
}
}
}

OutputStreamWriter

1
2
3
4
5
6
7
8
9
10
public class OutputStreamWriterTest {

public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream("test.txt");
//转换流
OutputStreamWriter out = new OutputStreamWriter(fos, "utf-8");
out.write("convert stream...");
out.close();
}
}

16.8 随机文件读写

RandomAccessFile是Java输入/输出流体系中功能最丰富的文件内容访问类,既可以读取文件内容,也可以向文件输出数据。与普通的输入/输出流不同的是,RandomAccessFile对象包含一个记录指针,用以标识当前读写处的位置,可以跳到文件任意位置读写数据。

RandomAccessFile类在创建对象时,除了指定文件本身,还需要指定一个mode参数,该参数指定RandomAccessFile的访问模式,该参数有如下四个值:

  • r:以只读方式打开指定文件。如果试图对该RandomAccessFile指定的文件执行写入方法则会抛出IOException
  • rw:以读取、写入方式打开指定文件。如果该文件不存在,则尝试创建文件
  • rws:以读取、写入方式打开指定文件。相对于rw模式,还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备,默认情形下(rw模式下),是使用buffer的,只有cache满的或者使用RandomAccessFile.close()关闭流的时候儿才真正的写到文件
  • rwd:与rws类似,只是仅对文件的内容同步更新到磁盘,而不修改文件的元数据

代码演示说明

文件随机读取

1
2
3
4
5
6
7
8
9
10
11
12
public class RandomFileTest {

public static void main(String[] args) throws Exception {
RandomAccessFile randomAccessFile = new RandomAccessFile("test.txt", "r");
randomAccessFile.seek(3);
int len = 0;
while((len = randomAccessFile.read()) != -1) {
System.out.println((char)len);
}

}
}