13.文件流

I/O流

1.常用的文件操作

new File(String pathname) //根据路径构建一个File对象
new File(File parent,String child) //根据父目录文件+子路径构建
new File(String parent,String child) //根据父目录+子路径构建

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
package 文件流;
import org.junit.Test;

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

//演示创建文件
public class FileCreate {
public static void main(String[]args){

}
//方式1:new File(String pathname) //根据路径构建一个File对象
@Test
public void create01() {
String filePath = "D:\\text.txt";
File file = new File(filePath);

try {
file.createNewFile();
System.out.println("文件创建成功");
}catch (IOException e){
e.printStackTrace();
}
}
//方式2:new File(File parent,String child) 根据父目录文件+子路径构建
@Test
public void create02(){
File parentFile = new File("D:\\");
String filename = "text2.txt";
//file只是一个对象,只有执行了createNewFile方法,才真正的创建了文件
File file = new File(parentFile,filename);
try{
file.createNewFile();
System.out.println("创建成功");
}catch (IOException e){
e.printStackTrace();
}
}
//方式3:new File(String parent,String child)//根据父目录+子路径构建
@Test
public void create03(){
String parentPath = "D:\\";
String filepath = "text3.txt";
File file = new File(parentPath, filepath);
try{
file.createNewFile();
System.out.println("创建成功");
}catch (IOException e){
e.printStackTrace();
}
}
}

2.常用的获取文件的相关信息

1.getName //获取文件名字
2.getAbsolutePath //获取文件的绝对路径
3.getParent //获取文件的父级目录
4.length //文件大小
5.exists //是否存在这个文件
6.isFile //是不是一个文件
7.isDirectory //是不是一个目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.junit.Test;
import java.io.File;
public class Fileinformation {
public static void main(String[]args) {

}
//获取文件的信息
@Test
public void info(){
//先创建文件对象
File file = new File("D:\\text1.txt");

//调用相应的方法的到对应信息即可
System.out.println("文件名字:"+file.getName());
System.out.println("文件绝对路径:"+file.getAbsolutePath());
System.out.println("文件的父级目录:"+file.getParent());
System.out.println("文件大小:"+file.length());
System.out.println("是否存在这个文件:"+file.exists());
System.out.println("是不是一个文件:"+file.isFile());
System.out.println("是不是一个目录"+file.isDirectory());
}
}

3.常用的目录操作和文件删除

1.mkdir //创建一级目录
2.mkdirs //创建多级目录
3.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
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
import org.junit.Test;
import java.io.File;
public class Directory_ {
public static void main (String[]args){

}
//判断d盘有没有text1,如果存在就删除
@Test
public void m1(){
String filepath = "D:\\text1.txt";
File file = new File(filepath);
if(file.exists()){
if (file.delete()){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
}else{
System.out.println("该文件不存在");
}
}
//在java中目录也被当作文件处理
@Test
public void m2(){
String filepath = "D:\\text2";
File file = new File(filepath);
if(file.exists()){
if (file.delete()){
System.out.println("删除成功");
}else{
System.out.println("删除失败");
}
}else{
System.out.println("该目录不存在");
}
}
//判断D:\\demo\\a\\b\\c目录是否存在,存在就显示存在,否则就被创建
@Test
public void m3(){
String directoryPath = "D:\\demo\\a\\b\\c";
File file = new File(directoryPath);
if(file.exists()){
System.out.println("该目录已经存在");
}else{
if (file.mkdirs()){
System.out.println("创建成功");
}else{
System.out.println("创建失败");
}
}
}
}

4.流的分类

1.按操作数据单位不同分为:字节流(二进制文件)、字符流(文本文件)
2.按数据流的流向不同分为:输入流、输出流
3.按流的角色的不同分为:节点流、处理流/包装流

(抽象基类) 字节流 字符流
输入流 inputStream Reader
输出流 OutputStream Writer

5.InputStream字节流常用子类

1.FileInputStream //文件输入流
2.BufferedInputStream //缓冲字节输入流
3.ObjectInputStream //对象字节输入流

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
57
58
59
60
61
62
63
64
65
66
67
68
69
//FileInputStream读取文件的两种方法
import org.junit.Test;
import java.io.FileInputStream;
import java.io.IOException;

//演示FileInputStream用法(字节输入流 文件--->程序)
public class FileInputStream_ {
public static void main(String []args){

}
@Test
//单个字节的读取,效率低
public void readFile01(){
String filePath = "D:\\hello.txt";
int readdata = 0;
FileInputStream fileInputStream = null;
try {
//创建了FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取一个字节的数据,如果没有输入可用,此方法将阻止,返回-1表示数据读取完毕
while((readdata = fileInputStream.read()) != -1){
System.out.print((char)readdata);
}

}catch (IOException e){
e.printStackTrace();
}finally {
//关闭文件流,释放资源
try{
fileInputStream.close();
}catch (IOException e){
e.printStackTrace();
}

}

}
@Test
//使用read(byte[] b) 读取文件
public void readFile02(){
String filePath = "D:\\hello.txt";
int readdata = 0;
//字节数组
byte[] buf = new byte[8];
int readlen = 0;
FileInputStream fileInputStream = null;
try {
//创建了FileInputStream对象,用于读取文件
fileInputStream = new FileInputStream(filePath);
//从该输入流读取最多b.length字节的数据到数组,此方法将阻塞,直到某些输入可用
//如果返回-1,就读取正常,并返回实际读取的字节数
while((readlen=fileInputStream.read(buf)) != -1){
System.out.print(new String(buf,0,readlen));
}

}catch (IOException e){
e.printStackTrace();
}finally {
//关闭文件流,释放资源
try{
fileInputStream.close();
}catch (IOException e){
e.printStackTrace();
}

}

}
}

6.OutputStream字节输出流

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
//演示用法FileOutputStream在a.txt文件中写入"hello world",如果文件不存在,就创建文件
import org.junit.Test;

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

public class FileOutputStream01 {
public static void main(String[]args){

}
@Test
//演示FileOutStream用法
public void writeFile(){
String filepath = "D:\\a.txt";
FileOutputStream fileOutputStream = null;
try {
//得到了FileOutStream对象
//1.new FileOutputStream(filepath); 创建方式会覆盖原有内容
//2.new FileOutputStream(filepath,true); 创建方式不会会覆盖原有内容,追加到后面
fileOutputStream=new FileOutputStream(filepath);
//写入一个字节
//fileOutputStream.write('a');
//写入字符串
String str = "hello world";
// fileOutputStream.write(str.getBytes());
//write(byte[] b,int off,int len)将len字节从位于偏移量off的指定字节数组写入此文件流
fileOutputStream.write(str.getBytes(),0,str.length());
}catch (IOException e){
e.printStackTrace();
}finally {
try {
fileOutputStream.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
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileCopy {
public static void main(String[]args){
//完成拷贝将F:\\桌面壁纸\\壁纸11.png拷贝到c:\\
//1.创建文件的输入流,将文件读入到程序
//2.创建文件的输出流,将文件拷贝到指定路径
String filepath = "F:\\桌面壁纸\\壁纸11.png";
String C = "E:\\壁纸11.png";
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
fileInputStream = new FileInputStream(filepath);
fileOutputStream = new FileOutputStream(C);
//定义一个字节数组,提高读取效率
byte[] buf = new byte[1024];
int readlen = 0;
while ((readlen=fileInputStream.read(buf)) != -1){
//读取到后,就写入到文件,通过fileOutputStream
//即一边读,一边写
fileOutputStream.write(buf,0, readlen);
}
System.out.println("拷贝ok");
}catch (IOException e){
e.printStackTrace();
}finally {
try {
//关闭输入输出流,释放资源
if (fileInputStream!=null){
fileInputStream.close();
}
if (fileOutputStream!=null){
fileOutputStream.close();
}
}catch (IOException e){
e.printStackTrace();
}
}


}
}

7.FileReader和FileWriter介绍

1.FileReader和FileWriter是字符流,即按照字符来操作io

7.1FileReader相关方法

1.new FileReader(File/String)
2.read:每次读取单个字符,返回该字符,如果到文件末尾就返回-1;
3.read(char[]):批量读取多个字符到数组,返回读取到的字符数,如果到文件末尾就返回-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
//使用FileReader从hello.txt读取内容
import java.io.FileReader;
import java.io.IOException;
public class FileReader_ {
public static void main(String[]args){
//先创建一个FileReader对象
String filePath = "D:\\hello.txt";
FileReader fileReader = null;
int data = 0 ;
try{
fileReader = new FileReader(filePath);
//循环读取
while((data = fileReader.read())!=-1){
System.out.print((char)data);
}
}catch (IOException e){
e.printStackTrace();
}finally {
if(filePath!=null){
try{
fileReader.close();
}catch (IOException e){
e.printStackTrace();
}
}
}

}

}

7.2FileWriter相关方法

1.new FileWriter(File/String):覆盖模式
2.new FileWriter(File/String,true):追加模式
3.write(int):写入单个字符
4.write(char[]):写入指定数组
5.write(char[],off,len):写入数组的指定部分
6.write(String):写入整个字符串
7.write(String,off,len):写入字符串的指定部分
8.String类:toCharArray:将String转换成char[]
9.FileWriter使用后,必须要关闭(close)或刷新(flush)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//将haozi0o0写入hello.txt文件中
import java.io.FileWriter;
import java.io.IOException;
public class FileWriter_ {
public static void main(String[]args){
String filepath = "D:\\hello.txt";
FileWriter fileWriter = null;
try {
fileWriter = new FileWriter(filepath);
fileWriter.write(new String("haozi0o0"));
}catch (IOException e){
e.printStackTrace();
}finally {
try{
fileWriter.close();
}catch (IOException e){
e.printStackTrace();
}

}

}
}

8.节点流和处理流

1.结点流是(从一个特定的数据源读取数据)文件和程序之间交互的,如FileReader、FileWriter
2.处理流也叫包装流,是连接在已存在的流(节点流或处理流)之上,为程序提供更强大的读写功能,如BufferredReader、BufferedWriter

9.节点流和处理流的区别

1.节点流是底层流,直接跟数据源相接
2.处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
3.处理流(也叫包装流)对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连
4.处理流的功能主要体现在以下两个方面
4.1性能的提高:主要以增加缓冲的方式来提高输入输出效率
4.2操作的便捷:处理流可能提供了一系列边界的方法来一次输入输出大批量的数据,使用更加灵活方便

10.处理流-BufferedReader和BufferedWriter

1.BufferedReader和BufferedWriter属于字符流,是按照字符来读取数据的,关闭时,只需要关闭外层流即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//使用BufferedReader读取文本文件,并显示在控制台
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class BufferedReader_ {
public static void main(String[] args) throws Exception {
String filePath = "D:\\hello.txt";
//创建bufferedReader
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
//读取
String line; //按行读取,效率高
//1.bufferedReader.readLine()是按行读取文件
//2.当返回null时,表示文件读取完毕
while ((line = bufferedReader.readLine()) != null){
System.out.print(line);
}
//关闭流,只需要关闭bufferedReader,因为低等会自动关闭节点流
bufferedReader.close();
}
}

2.BufferedWrite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//将hello world写入文件hello.txt里
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWrite_ {
public static void main(String[] args) throws IOException{
String filePath = "D:\\hello.txt";
//new FileWriter(filePath,true) 表示追加输入
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath,true));
bufferedWriter.write("hello1 world");
bufferedWriter.newLine(); //插入换行
bufferedWriter.write("hello2 world");
bufferedWriter.newLine(); //插入换行
bufferedWriter.write("hello3 world");
bufferedWriter.close();
}
}

3.实现文件拷贝,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
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.io.*;
//不要去操作二进制文件,常见的二进制文件有[声音、视频、doc、pdf等]
public class BufferedCopy_ {
public static void main(String[] args) {
String s1 = "D:\\hello.txt";
String s2 = "D:\\hello2.txt";
BufferedReader br = null;
BufferedWriter bw = null;
String line;
try {
br = new BufferedReader(new FileReader(s1));
bw = new BufferedWriter(new FileWriter(s2));
//readLine 是读取一行内容,没有换行
while ((line = br.readLine()) != null){
//每读取一行就写入
bw.write(line);
//插入一个换行
bw.newLine();
}
System.out.println("拷贝完成");
}catch (IOException e){
e.printStackTrace();
}finally {
try{
if (br!=null){
br.close();
}
if(bw!=null){
bw.close();
}
}catch (IOException e){
e.printStackTrace();
}

}

}
}

11.处理流BufferedInputStream和BufferedOutputStream

1.BufferedInputStream、BufferedOutputStream,可以处理二进制文件,它们是字节流,字节流也可以操作二进制文件,例如文本文件

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
//拷贝文件C:\Users\haozi\开箱子.mp4
import java.io.*;

public class BufferedCopy_ {
public static void main(String[] args) {
String yuan = "C:\\Users\\haozi\\开箱子.mp4";
String mudi = "D:\\开箱子.mp4";
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
bis = new BufferedInputStream(new FileInputStream(yuan));
bos = new BufferedOutputStream(new FileOutputStream(mudi));
//循环的读取文件,并写入到目的目录
byte[] buff = new byte[1024];
int readLen = 0;
while ((readLen = bis.read(buff))!=-1){
bos.write(buff,0,readLen);
}
System.out.println("文件拷贝完成");
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if (bis!=null){
bis.close();
}
if (bos!=null){
bos.close();
}
}catch (IOException e){
e.printStackTrace();
}
}

}
}

12.对象处理流

需求:将int num = 100这个int数据保存到文件中,注意不是100数组,而是int 100,并且,能够从文件中直接恢复int 100
以上的要求,就是能够将基本数据类型或者对象进行序列化和反序列化操作
1.序列化就是在保存数据时,保存数据的值和数据类型
2.反序列化就是在恢复数据时,恢复数据的值和数据类型
3.需要让某个对象支持序列化机制,则必须让其类是可序列化的,为了让某个类是可序列化,该类必须实现如下两个接口之一:
Serializable //这是一个标记接口,如果不实现接口则无法进行序列化
Externalizable
4.ObjectOutputStream //提供序列化功能

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
//使用ObjectOutputStream序列化基本数据类型和一个Dog(name,age)对象,并保存到data.dat文件中
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class ObjectOutStream_ {
public static void main(String[] args) throws Exception{
String filePath = "D:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到e:\data.dat
oos.writeInt(100); //int -> Integer(实现了 Serializable)
oos.writeBoolean(true); //boolean->Boolean(实现了 Serializable)
oos.writeChar('a'); //char->Character
oos.writeDouble(9.5); //double->Double
oos.writeUTF("haozi"); //String
//保存一个dog对象
oos.writeObject(new Dog("haozi",18));
oos.close();
System.out.println("数据保存完毕(序列化)");
}
}
//如果需要序列化某个类的对象,实现Serializable
class Dog implements Serializable {
private String name;
private int age;

public Dog(String name,int age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}

5.ObjectInputStream //提供反序列化功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Scanner;

public class ObjectInputStream_ {
public static void main(String[] args) throws IOException,ClassNotFoundException {
Scanner sc = new Scanner(System.in);

String filePath = "D:\\data.dat";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
//读取(反序列化)的顺序一定要和序列化的顺序一样,否则会发生异常
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
Object dog = ois.readObject();
System.out.println(dog.getClass());
System.out.println(dog);
//关闭流
ois.close();
}
}

注意事项:
1.读写顺序要一致
2.要求实现序列化或反序列化对象,需要实现Serializable
3.序列化的类中建议添加SerialVersionUID,为了提高版本兼容性
private static final long serialVersionUID = 1L;
4.序列化对象时,默认将里面所有属性都进行序列化,但除了static或transient修饰的成员
5.序列化对象时,要求里面属性的类型也需要实现序列化接口
6.序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化

13.转换流:InputStreamReader和OutputStreamWriter

1.InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成Reader(字符流)
2.OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流)
3.当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
4.可以在使用时指定编码格式(比如utf-8,gbk,gb2312,ISO8859-1等)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//将字节流FileInputStream包装成(转换成)字符流InputStreamReader,对文件进行读取(按照utf-8/gbk格式),进而在包装成BufferedReader
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
//这里的a.txt的编码格式为ANSI
String filepath = "D:\\a.txt";
InputStreamReader isr = new InputStreamReader(new FileInputStream(filepath),"gbk");
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
System.out.println("读取内容="+s);
br.close();

}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
//将字节流FileOutputStream包装成(转换成)字符流OutputStreamWriter,对文件进行写入(按照gbk格式,可以指定其他,比如UTF-8)
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String filepath = "D:\\a.txt";
OutputStreamWriter isd = new OutputStreamWriter(new FileOutputStream(filepath),"UTF-8");
isd.write("hi,my name is 耗子");
isd.close();
}
}

13.文件流
http://example.com/2023/03/18/java/13.文件流/
作者
haozi0o0
发布于
2023年3月18日
许可协议