0%

java-Day13——IO

File类

File类的理解

  • File类位于java.io包下。
  • File类的一个对象,对应于操作系统下的一个文件或一个文件目录
  • File类中声明了新建、删除、获取名称、重命名等方法,并没有涉及到文件内容的读写操作。要想实现文件内容的读写,需要使用io流。
  • File类的对象,通常是作为io流操作的文件的端点出现。
    • 代码层面,将File类对象作为参数传递到IO流相关类的构造器中。

构造器

  • File(String pathname) :以pathname为路径创建File对象,可以是绝对路径或者相对路径
  • File(String parent, String child):以parent为父路径,child为子路径创建file对象
  • File(File parent, String child) 根据一个父File对象和子文件路径创建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
public class FileTest {
@Test
public void test1(){
/* public File(String pathname)
方式1:绝对路径:windows操作系统为例,包括盘符在内的文件或文件目录的完整路径
方式2:相对路径:相对于某一个文件目录的相对位置
在IDEA中:
单元测试方法:相对于当前Module来讲
main方法:相对于当前project来讲

*/
File file1 = new File("d:/io\\hello.txt");
File file2 = new File("abc");
}
@Test
public void test2(){
// public File(String parent, String child)
// 参数1:一定是一个文件目录(String方式),参数2:可以是一个文件,也可以是一个文件目录
File file1 = new File("d:\\io","abc.txt");
File file2 = new File("abc","ab");
//参数1:一定是一个文件目录,参数2:可以是一个文件,也可以是一个文件目录
// public File(File parent, String child)
File file3 = new File(file2,"ab");
}
}

方法

获取文件和目录基本信息

  • String getName():获取名称
  • String getPath():获取路径
  • String getAbsolutePaht():获取绝对路径
  • File getAbsoluteFile():获取绝对路径表示的文件
  • String getParent():获取上层文件目录路径。不能获取目录的长度
  • long length():获取文件长度(字节数).不能获取目录的长度
  • long lastModified():获取最后一次的修改时间,毫秒值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
public void test(){
File file = new File("hello.txt");
System.out.println(file.getName());//hello.txt
System.out.println(file.getPath());//hello.txt 因为是相对路径
System.out.println(file.getAbsolutePath());//D:\javaSE\JavaSE\Chapter15_file\hello.txt
System.out.println(file.getAbsoluteFile());////D:\javaSE\JavaSE\Chapter15_file\hello.txt返回的是对象
System.out.println(file.getParent());//null 因为是相对路径
System.out.println(file.length());//6
System.out.println(file.lastModified());//1697208159548时间戳

File file1 = new File("D:\\javaSE\\Chapter15_file\\hello.txt");
System.out.println(file1.getName());//hello.txt
System.out.println(file1.getPath());//D:\javaSE\Chapter15_file\hello.text
System.out.println(file1.getAbsolutePath());//D:\javaSE\Chapter15_file\hello.text
System.out.println(file1.getAbsoluteFile());//D:\javaSE\Chapter15_file\hello.text
System.out.println(file1.getParent());//D:\javaSE\Chapter15_file
System.out.println(file1.length());
System.out.println(file1.lastModified());
}

列出目录的下一级

  • String[] list():返回一个String数组,表示该File目录中的所有子文件或目录。
  • File[] listFiles():返回一个File数组,表示该File目录中的所有子文件或目录。
1
2
3
4
5
6
7
8
9
10
11
12
13
@Test
public void test2(){
File file1 = new File("D:\\javaSE\\javaSE");
String[] fileArr = file1.list();
for(String s:fileArr){
System.out.println(s);
}

File[] files = file1.listFiles();
for(File f:files){
System.out.println(f);
}
}

重命名

  • file1.renamTo(file2):把文件重命名为指定的文件路径。file1必须存在且file2不存在
1
2
3
4
5
6
7
8
@Test
public void test3(){
File file1 = new File("hello.txt");
File file2 = new File("D:\\javaSE\\JavaSE\\Chapter15_file\\hello2.txt");

boolean renameSuccess = file1.renameTo(file2);
System.out.println();
}

判断功能的方法

  • boolean exits():此File表示的文件或目录是否实际存在
  • boolean isDirectory():此File表示的是否为目录
  • boolean isFile():此File表示的是否为文件
  • boolean canRead():判断是否可读
  • boolean canWrite():判断是否可写
  • boolean isHidden():判断是否隐藏
1
2
3
4
5
6
7
8
9
10
@Test
public void test4(){
File file1 = new File("hello2.txt");
System.out.println(file1.exists());
System.out.println(file1.isDirectory());
System.out.println(file1.isFile());
System.out.println(file1.canRead());
System.out.println(file1.canWrite());
System.out.println(file1.isHidden());
}

创建和删除类型

  • boolean createNewFile():创建文件。若文件存在,则不创建,返回false
  • boolean mkdir():创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上册目录不存在,也不创建
  • boolean mkdirs():创建文件目录。如果上层文件目录不存在,一并创建
  • boolean delete():删除文件或文件夹
  • 注意:java中的删除不走回收站。要删除一个文件目录,请主要该文件目录内不能包含文件或者文件目录

IO流

java中对于数据的输入/输出操作以“流”的方式进行,可以看作是一种数据的流动

流的分类

  • 流向的不同:输入流、输出流
  • 处理单位的不同:字节流、字符流
  • 流的角色的不同:节点流、处理流

XaZad.png

流的API

IO流共涉及40多个类,实际上非常规则,都是从如下4个抽象基类派生的。

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

节点流

字符流

FileReader\FileWriter的使用

执行步骤:

  1. 创建读或写的File类对象
  2. 创建输入流或输出流
  3. 具体的读入或写出的过程
    1. 读入:read(char[] cbuffer)
    2. 写出:write(String str)/ write(char[] cbuffer,0,len)
  4. 关闭流资源

注意点:

  1. 因为涉及流资源关闭操作,所以出现异常的花,需要使用try-catch-finally的方式来处理异常

  2. 对于输入流来讲,要求File类的对象对应的物理磁盘上的文件必须存在。否则会报FileNotFoundException

    对于输出流来讲,File类的对象对应的物理磁盘上的文件可以不存在。

    • 如果此文件不存在,则在输出的过程中,会自动创建此文件,并写出数据到此文件中。
    • 如果此文件存在,使用FileWriter(file file)或FileWriter(File file, false):输出数据过程中,会创建同名的文件对现有的文件进行覆盖。
    • FileWriter(File 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
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
@Test
public void test() throws IOException {
FileReader fileReader = null;
try {
//1.创建File类的对象,对应着hello.txt文件
File file1 = new File("hello.txt");

//2.创建输入型的字符流,用于读取数据
fileReader = new FileReader(file1);

//3.读取数据,并显示在控制台
//方式2.read(char[] cbuffer)
char[] cbuffer = new char[5];
int len;
while((len=fileReader.read(cbuffer))!= -1){
for(int i =0; i<len;i++){
System.out.println(cbuffer[i]);
}
}

} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//4.流资源的关闭操作
try {
if(fileReader != null){
fileReader.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

/*
* 需求:将内存中的数据写出到指定的文件中
*
* */
@Test
public void test2() {
FileWriter fw = null;
try {
//1.创建File类的对象,指明要写出的文件的名称
File file = new File("info.txt");
//2.创建输出流
fw = new FileWriter(file,false);//append是否在原文件追加

//3.写出的具体过程
//输出的方法:write(String str)/write(char[] cdata)
fw.write("I love");
fw.write("you love");
fw.write("xixi");
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if(fw!=null){
fw.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/*
* 需求:复制一份hello.txt文件,命名为hello_copy.txt
* */
@Test
public void test1() {
FileReader fr = null;
FileWriter fw = null;
try {
//1.创建File类的对象
File srcFile = new File("hello.txt");
File destFile = new File("hello_copy.txt");

//2.创建输入流、输出流
fr = new FileReader(srcFile);
fw = new FileWriter(destFile);

//3.数据的读入和写出的过程
char[] cbuffer = new char[5];
int len;//记录每次读入到cbuffer中的字符个数
while ((len = fr.read(cbuffer)) != -1) {
fw.write(cbuffer, 0, len);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if(fw!=null){
fw.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
if(fr!=null) {
fr.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

字节流

FileInputStream\FileOutputStream

使用步骤

  1. 创建读或写的File类对象
  2. 创建输入流或输出流
  3. 具体的读入或写出的过程
    1. 读入:read(byte[] buffer)
    2. 写出:write(byte[] buffer,0,len)
  4. 关闭流资源

注意点

  • 在文件流的注意点基础之上。 字符流只能用来操作文本文件,不能用来处理非文本文件。
  • 对于字节流,通常是用来处理非文本文件。但是涉及到文本文件的复制操作,也可以使用字节流。

说明:

文本文件:.txt、 .java、.c

非文本文件:.doc 、 .xls 、.jpg、.pdf 、.mp3

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
public class FileStreamTest{
@Test
public void test() {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
//1.创建相关的File类的对象
File srcFile = new File("xxx.jpg");
File desFile = new File("xxx_copy.jpg");

//2.创建相关的字节流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(desFile);

//3.数据读取和写出
byte[] buffer = new byte[1024]; //1kb
int len;
while((len = fis.read(buffer))!=-1){
fos.write(buffer,0,len);
}

} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//4.关闭资源
try {
if(fos!=null){
fos.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
try {
if(fos!=null){
fis.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}

缓冲流

抽象基类 节点流(文件流) 缓冲流
InputStream FileInputStream BufferedInputStream
OutputStream FileOutputStream BufferedOutputStream
Reader FileReader BufferedReader
Writer FileWriter BufferedWriter

缓冲流的作用

减少与磁盘的交互,提升文件读写的效率。

缓冲区:内部提供了一个数组,将读取或写出的数据,现在此数组中缓冲。达到一定程度时,集中性的写出。

4个缓冲流

处理非文本文件的字节流: 方法

  • BufferedInputStream read(byte[] buffer)

  • BufferedOutputStream write(byte[] buffer,0,len)

处理文本文件的字符流

  • BufferedReader read(char[] cbuffer) / readLine()
  • BufferedWriter write(char[] cbuffer, 0, len)

实现步骤

  1. 创建File对象、流的对象(包括文件流、缓冲流)

  2. 使用缓冲流实现读取数据或写出数据的过程

    ​ 读取:int read(char[] cbuf/byte[] buffer) :每次将数据读入到cbuf/buffer数组中,并返回读入到数组中

    ​ 写出: void write(String str)/write(char[] cbuf):将str或cbuf写出到文件中

    ​ void write(byte[] buffer) 将byte写出到文件中

  3. 关闭资源

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 BufferInputTest {
@Test
public void test() {
FileInputStream fis = null;
FileOutputStream fos = null;
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//1.创建相关的File类的对象
File srcFile = new File("xxx.jpg");
File desFile = new File("xxx_copy.jpg");

//2.创建相关的字节流、缓冲流
fis = new FileInputStream(srcFile);
fos = new FileOutputStream(desFile);

bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);

//3.数据读取和写出
byte[] buffer = new byte[1024]; //1kb
int len;
while((len = bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}

} catch (IOException e) {
throw new RuntimeException(e);
} finally {
//4.关闭资源
//外层流的关闭会自动关闭内存流
try {
if(bis!=null){
bis.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
try {
if(bos!=null){
bos.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}

转换流

字符编码:字符、字符串、字符数组–》字节、字节数组

字符解码:字节、字节数组–》字符、字符串、字符数组

如果希望程序在读取文本时,不出现乱码

解码时使用的字符集必须与当初编码时使用的字符集一致

解码集必须要与编码集兼容。

作用:实现字节与字符之间的转换

API

InputStreamReader:将一个输入型的字节流转换为输入型的字符流

OutputStreamWriter:讲一个输出型的字符流转换为输出型的字节流

关于字符集的理解

  • ascii:主要用来存储a,b,c英文字符和1,2,3常用标点字符。每个字符1个字节。

  • iso-8859-1:了解,每个字符占用1个字符。向下兼容ascii

  • gbk:用来存储包括中文简体繁体,a,b,c等英文字符和1,2,3,常用的标点符号等字符。中文字符使用2个字节,向下兼容ascii。英文1个字节。

  • utf-8:可以用来存储世界范围内主要的语言的所有的字符。使用1-4个不等的字节表示一个字符。中文使用3个字节,英文1个。

内存中的字符

一个字符(char)占用2个字节。在内存使用的字符集称为Unicode字符集。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Test
public void test2() throws IOException{
//1.造文件
File file1 = new File("xxx_gbk.txt");
File file2 = new File("xxx_gbk2utf8");
//2.造流
FileInputStream fis = new FileInputStream(file1);
InputStreamReader isr = new InputStreamReader(fis,"GBK");

FileOutputStream fos = new FileOutputStream(file2);
OutputStreamWriter oos = new OutputStreamWriter(fos,"utf8");

//3.读写过程
char[] cBuffer = new char[1024];
int len;
while((len = isr.read(cBuffer))!=-1){
oos.write(cBuffer,0,len);
}
System.out.println("操作完成");
//4.关闭资源

oos.close();
isr.close();
}

对象流

说明

考虑将内存中定义的变量保存在文件中

数据流(只支持基本数据类型和字符串的读写,而不支持其他jav对象的类型)

  • DataOutputStream:将内存中基本数据类型、String类型的变量写入具体的文件中
  • DataInputStream:将文件中保存的数据还原为内存的基本数据类型、String类型的变量。

对象流

  • ObjectOutputStream:将java基本数据类型和对象写入字节输出流中。通过在流中使用文件可以实现java各种基本数据类型的数据以及对象的持久存储
  • ObjectInputStream:ObjectInputStream对以前使用ObjectOutputStream写出的基本数据类型的数据和对象进行读入操作,保存在内存中。

对象的序列化机制

对象序列化机制允许把内存中java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输到另一个网络节点。//当其他程序获取了这种二进制流,就可以恢复成原来的java对象。

  • 序列化过程:ObjectOutputStream流实现。将内存中的java对象保存在文件中或通过网络传输出去
  • 反序列化过程:使用ObjectInputStream实现。将文件中的数据或网络传输过来的数据还原为内存中的java的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ObjectOutputTest {
@Test
public void test1() throws IOException {
File file = new File("xx.txt");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
oos.writeUTF("xixihaha");
oos.writeObject("xixihaha");
oos.flush();
oos.close();
}

@Test
public void test2() throws IOException, ClassNotFoundException {
File file = new File("xx.txt");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
String str1 = ois.readUTF();
String str2 = (String) ois.readObject();
System.out.println(str1);
System.out.println(str2);

ois.close();
}
}

自定义类实现序列化的要求

  • 自定义类需要实现接口:Serializable
  • 要求自定义类声明一个全局常量:static final long serialVersionUID = 42234234L;用于唯一的标识当前的类
  • 要求自定义类的各个属性必须是可序列化的。
    • 对于基本数据类型的属性:默认可序列化
    • 对于引用数据类型:需要实现Serializable接口

注意点:

  1. 如果不声明全局常量,系统会自动声明生产一个针对于当前类的serialVersionUID。

    如果修改此类的话,会导致serialVersionUID变换,进而导致反序列化时,出现InvalidClassException异常

  2. 类中的属性如果声明为transient或static,则不会序列化。

其他流

标准输入流、标准输出流、system.in、system.out

-------------本文结束感谢您的阅读-------------