IO
目标:
- 能够独立使用
File
类的常用方法 应用 - 能够说出什么是相对路径和绝对路径 理解
- 能够独立使用字节流写数据 应用
- 能够独立使用字节流读数据 应用
- 能够独立使用字节流复制文件 应用
- 能够独立使用缓冲流复制文件 应用
# IO流概述和分类(理解)
在电脑上的数据有三种存储方式,外存、内存、缓存。比如硬盘、磁盘、U盘等都是外存,我们常说的内存条就是内存,最后还有CPU里面的缓存。这三类以存储空间进行排序:外存 > 内存 > 缓存,以访问速度进行排序:缓存 > 内存 > 外存。之所以使用这三种设备,就是为了解决因CPU速度与外界存储设备访问速度之间的差距导致的电脑性能问题,也就是我们知道的木桶短板问题。下面我们要学习的IO流就是来实现内存与外存数据交互的。
# IO流介绍
- IO: 输入/输出(Input/Output)
- 流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质就是数据传输
- IO流就是用来处理设备间数据传输问题的,常见的应用:文件复制;文件上传;文件下载
# IO流的分类
- 按照数据的流向
- 输入流:读数据
- 输出流:写数据
- 按数据类型分
- 字节流
- 字节输入流
- 字节输出流
- 字符流
- 字符输入流
- 字符输出流
- 字节流
# IO流的使用场景
- 如果操作的是村文本文件,优先使用字符流
- 如果操作的是图片、视频、音频等二进制文件,优先使用字节流
- 如果不确定文件类型,优先使用字节流,字节流是通用的流。
# 文件操作类
通过上面的介绍,现在大家应该对IO流有了解了,Java IO流的主要操作对象就是文件,那接下来我们就要来看在Java中怎么表示文件?
在Java中,File
是java.io
包中唯一代表磁盘文件本身的对象,也就是说,如果希望在程序中操作文件和目录,就都可以通过File
类来完成。File
类定义了一些方法来操作文件,如新建、删除、重命名文件和目录等。
注意
File
类不能访问文件内容本身,如果需要访问文件内容本身,则需要使用输入/输出流。
那怎么来构造或者创建File
类对象呢?File
类提供了如下三种形式的构造方法:
File(String path)
:如果path
是实际存在的路径,则该File
对象表示的是目录;如果path
是文件名,则该File
对象表示的是文件。File(String path, String name)
:path
是路径名,name
是文件名File(File dir, String name)
:dir
是路径对象,name
是文件名
使用上面任意一个构造方法都可以创建一个File
对象,然后调用其提供的方法对文件进行操作。下面这这表列出了File
类的常用方法及说明。
方法名称 | 说明 |
---|---|
boolean canRead() | 测试应用程序是否能从指定的文件中进行读取 |
boolean canWrite() | 测试应用程序是否能写当前文件 |
boolean delete() | 删除当前对象指定的文件 |
boolean exists() | 判断当前File 是否存在 |
String getAbsolutePath() | 返回由该对象表示的文件的绝对路径名 |
String getName() | 返回表示当前对象的文件名或路径名(如果是路径,则返回最后一级子路径名) |
String getParent() | 返回当前File 对象所对应的目录(最后一级子目录)的父目录名 |
boolean isAbsolute() | 测试当前File 对象表示的文件是否为一个绝对路径名。该方法消除了不同平台的差异,可以直接判断File 对象是否为绝对路径。在UNIX/Linux 等系统上,如果路径名以/ 开头,则表名该File 对象对应一个绝对路径;在Windows 系统上,如果路径开头是盘符,则说明它是一个绝对路径。 |
boolean isDirectory() | 测试当前File 对象表示的文件是否为一个路径 |
boolean isFile() | 测试当前File 对象表示的文件是否为一个普通文件 |
long lastModified() | 返回当前File 对象表示的文件最后修改的时间 |
long length() | 返回当前File 对象表示的文件长度 |
String[] list() | 返回当前File 对象指定的路径文件列表 |
String[] list(FilenameFilter) | 返回当前File 对象指定的目录中满足指定过滤器的文件列表 |
String[] mkdir() | 创建一个目录,它的路径名由当前File 对象指定 |
boolean mkdirs() | 创建一个目录,它的路径名由当前File 对象指定 |
boolean renameTo(File) | 将当前File 对象指定的文件更名为给定参数File 指定的路径名 |
实现代码如下:
package com.itheima.file;
import java.io.File;
import java.util.Date;
/**
* 文件操作类演示案例一
* @author sunyy
* @version 0.0.1
* @since 2022.10.28
*/
public class FileDemo1 {
public static void main(String[] args) {
/**
* Windows的路径分割符使用反斜线"\",而Java程序中的反斜线表示转义字符,所以如果需要在
* Windows的路径下包含反斜线,则应该使用两条反斜线或直接使用斜线"/"也可以。Java程序
* 支持将斜线当成平台无关的路径分隔符。
* 假设在Windows操作系统中有一文件"D:\itcast\Temp\io\1.txt",在Java中使用的时候,
* 其路径的写法应该为"D:/itcast/Temp/io/1.txt"或者"D:\\itcast\\Temp\\io\\1.txt"
*/
String path = "D:\\itcast\\Temp\\io"; // 指定文件所在的目录
File file = new File(path, "1.txt"); // 建立File变量,并设定由file变量引用
System.out.println("1.txt文件信息如下:");
System.out.println("===================================");
System.out.println("文件长度:" + file.length() + " 字节");
System.out.println("文件或者目录:" + (file.isFile() ? "是文件" : "不是文件"));
System.out.println("文件或者目录:" + (file.isDirectory() ? "是目录" : "不是目录"));
System.out.println("是否可读:" + (file.canRead() ? "可读" : "不可读"));
System.out.println("是否可写:" + (file.canWrite() ? "可写" : "不可写"));
System.out.println("是否隐藏:" + (file.isHidden() ? "隐藏文件" : "非隐藏文件"));
System.out.println("最后修改日期:" + new Date(file.lastModified()));
System.out.println("文件名称:" + file.getName());
System.out.println("文件路径:" + file.getPath());
System.out.println("绝对路径:" + file.getAbsolutePath());
}
}
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
在上述代码中File
类构造方法的第一个参数指定文件所在位置,这里使用D:\\itcast\\Temp\\io
作为文件的实际路径;第二个参数指定文件名称。创建的File
类对象为file
,然后通过file
调用方法获取相应的属性,最终运行效果如下所示。
1.txt文件信息如下:
===================================
文件长度:4186 字节
文件或者目录:是文件
文件或者目录:不是目录
是否可读:可读
是否可写:不可写
是否隐藏:隐藏文件
Disconnected from the target VM, address: '127.0.0.1:50029', transport: 'socket'
最后修改日期:Fri Oct 28 21:02:05 CST 2022
文件名称:1.txt
文件路径:D:\itcast\Temp\io\1.txt
绝对路径:D:\itcast\Temp\io\1.txt
2
3
4
5
6
7
8
9
10
11
12
13
# 创建和删除文件
File
类不仅可以获取已知文件的属性信息,还可以在指定路径创建文件,以及删除一个文件。创建文件需要调用createNewFile()
方法,删除文件需要调用delete()
方法。无论是创建还是删除文件通常先调用exists()
方法判断文件是否存在。
示例2:假设要在D:\\itcast\\Temp\io\\
目录下创建一个2.txt
文件,程序启动时会检测改文件是否存在,如果不存在则创建;如果存在则删除它在创建。
代码如下:
package com.itheima.file;
import java.io.File;
import java.io.IOException;
/**
* 创建和删除文件演示代码
* @author sunyy
* @version 0.0.1
* @since 2022.10.28
*/
public class FileDemo2 {
public static void main(String[] args) throws IOException {
String filePath = "D:/itcast/Temp/io/2.txt";
File file = new File(filePath); // 创建指向文件的File对象
if (file.exists()) { // 判断文件是否存在
file.delete(); // 存在则先删除
}
file.createNewFile(); // 再创建
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
运行程序之后可以发现,在D:\itcast\Temp\io
目录中已经创建好了2.txt
文件。但是如果在不同的操作系统中,路径的分隔符是不一样的,例如:
- Windows 中使用反斜杠
\
表示目录的分隔符 - Linux中使用正斜杠
/
表示目录的分隔符
那么既然Java程序本身具有可一致性的特点,则在编写路径时最好可以根据程序所在的操作系统自动使用符合本地操作系统要求的分隔符,这样才能达到可移植性的目的。要实现这样的功能,就需要使用File
类中提供的两个常量。
代码修改如下:
package com.itheima.file;
import java.io.File;
import java.io.IOException;
/**
* 创建和删除文件演示代码
*
* @author sunyy
* @version 0.0.1
* @since 2022.10.28
*/
public class FileDemo2 {
public static void main(String[] args) throws IOException {
// String filePath = "D:/itcast/Temp/io/2.txt";
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp" + File.separator + "io" + File.separator + "2.txt";
File file = new File(filePath); // 创建指向文件的File对象
if (file.exists()) { // 判断文件是否存在
file.delete(); // 存在则先删除
}
file.createNewFile(); // 再创建
}
}
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
程序的运行结果和前面程序一样,但是此时的程序可以在任意的操作系统中使用。
注意
**在操作文件时一定要使用File.separator
表示分隔符。**在程序的开发中,往往会使用Windows开发环境,因为在Windows操作系统中支持的开发工具较多,使用方便,而在程序发布时往往是直接在Linux或其他操作系统上部署,所以这时如果不使用File.separator
,则程序运行就有可能存在问题。
# 创建和删除目录
File
类除了对文件的创建和删除外,还可以创建和删除目录。创建目录需要调用mkdir()
方法,删除目录需要调用delete()
方法。无论是创建还是删除目录都可以调用exists()
方法判断目录是否存在。
示例3:编写一个程序判断D:\itcast\Temp\io
是否存在log
目录,如果存在则先删除再创建。实现代码如下:
package com.itheima.file;
import java.io.File;
/**
* 创建和删除目录演示案例
* @author sunyy
* @version 0.0.1
* @since 2022.10.28
*
*/
public class FileDemo3 {
public static void main(String[] args) {
String dirPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "log"; // 指定目录位置
File dir = new File(dirPath); // 创建File对象
if (dir.exists()) {
boolean deleteSuccess = dir.delete();
System.out.println(deleteSuccess ? "删除成功" : "删除失败");
}
boolean mkSuccess = dir.mkdir(); // 创建目录
System.out.println(mkSuccess ? "创建成功" : "创建失败");
}
}
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
# 遍历目录
通过遍历目录可以在指定的目录中查找文件,或者显示所有的文件列表。File类的list()
方法提供了遍历目录功能,该方法有如下两种重载形式。
String[] list()
该方法表示返回由File
对象表示目录中所有文件和子目录名称组成的字符串数组,如果调用的File
对象不是目录,则返回null
。
提示
**list()
方法返回的数组中仅包含文件名称,而不包含路径。**而且不保证所得数组中的相同字符串以特定顺序出现,特别是不保证它们按字母顺序排序。
String[] list(FilenameFilter filter)
该方法的作用与list()
方法相同,不同的是返回数组中仅包含符合filter
过滤器的文件和目录,如果filter
为null
,则接受所有名称
示例4:假设要遍历D:\itcast\Temp\io
下的所有文件和目录,并显示文件或目录名称、类型及大小。使用list()
方法的实现代码如下:
package com.itheima.file;
import java.io.File;
import java.io.FilenameFilter;
/**
* 遍历目录案例
* @author sunyy
* @version 0.0.1
* @since 2022.10.28
*/
public class FileDemo4 {
public static void main(String[] args) {
String dirPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "log"; // 指定目录位置
/**
* 调用不带参数的list()方法
*/
File dir = new File(dirPath);
String filesInDir[] = dir.list();
for (String fileName : filesInDir) {
// 遍历目录下的文件或目录名
System.out.print(fileName + "\t\t");
File file = new File(dirPath + File.separator + fileName);
System.out.print(file.isFile() ? "文件" : "文件夹" + "\t\t");
System.out.println(file.length() + " 字节");
}
/**
* 调用带过滤器参数的list()方法
*/
String docsInDir[] = dir.list(new DocFilter());
for (String docName : docsInDir) {
// 遍历目录下所有word文档
System.out.println("=================Word文档===================");
System.out.print(docName + "\t\t");
File file = new File(dirPath + File.separator + docName);
System.out.print(file.isFile() ? "文件" : "文件夹" + "\t\t");
System.out.println(file.length() + " 字节");
}
}
}
/**
* word文件过滤器
* @author sunyy
* @version 0.0.1
* @since 2022.10.28
*/
class DocFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".doc");
}
}
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
提示
由于list()
方法返回的字符数组中仅包含文件名称,因此未了获取文件类型和大小,必须先转换为File
对象再调用其方法。在示例4代码中我们还调用了带过滤其参数的list()
方法。如果希望只列出目录下的某些文件,就需要实现java.io.FilenameFilter
接口,并在accept()
方法中指定允许的文件类型。
执行结果如下:
1 文件夹 0 字节
3.doc 文件 9216 字节
a.txt 文件 0 字节
b.txt 文件 0 字节
c 文件夹 0 字节
新建文本文档.txt 文件0 字节
=================Word文档===================
3.doc 文件 9216 字节
2
3
4
5
6
7
8
# 字节流
- 字节流抽象基类
InputStream
:这个抽象类是表示字节输入流的所有类的超类OutputStream
:这个抽象类是表示字节输出流的所有类的超类- 子类命名特点:子类名称都是以其父类名作为子类名的后缀
- 字节输出流
FileOutputStream(String name)
:创建文件输出流以指定的文件名称写入文件
- 使用字节输出流写数据的一般步骤
- 创建字节输出流对象(调用系统功能创建文件,创建字节输出流对象,让字节输出流对象指向文件)
- 调用字节输出流对象的写数据方法
- 释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
示例代码1:
package com.itheima.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 字节输出流代码示例1
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileOutputStreamDemo1 {
public static void main(String[] args) throws IOException {
/**
* 1. 创建字节输出流对象
* 注意:
* 1. 如果文件不存在,会帮我们自动创建
* 2. 如果文件已存在,会把文件内容清空
*/
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "fos_demo1.txt"; // 指定字节输出流对象
FileOutputStream fos = new FileOutputStream(filePath);
/**
* 2. 讲指定的字节写入此文件输出流
*/
fos.write(104);
fos.write(101);
fos.write(108);
fos.write(108);
fos.write(111);
/**
* 3. 释放资源
*/
fos.close();
}
}
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
# 字节流写数据的三种方式
方法名 | 说明 |
---|---|
void write(int b) | 将指定的字节写入此文件输出流,一次写一个字节数据 |
void write(byte[] b) | 将b.length 字节从指定的字节数组写入文件输出流,一次写一个字节数组数据 |
void write(byte[] b, int off, int len) | 将len 字节从指定的字节数组开始,从偏移量off 开始写入此文件输出流,一次写一个字节数组的部分数据 |
示例代码2:
package com.itheima.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 字节输出流示例代码2
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileOutputStreamDemo2 {
public static void main(String[] args) throws IOException {
/**
* 1. 创建字节输出流对象
* 注意:
* 1. 如果文件不存在,会帮我们自动创建
* 2. 如果文件已存在,会把文件内容清空
*/
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "fos_demo2.txt"; // 指定字节输出流对象
FileOutputStream fos = new FileOutputStream(filePath);
/**
* 2. 输出内容:从偏移量off位置,将len长度的字节从指定的字节数组开始写入文件输出流
*/
String content = "Hello World!";
byte[] bys = content.getBytes();
fos.write(bys, 6, 6);
/**
* 3. 释放资源
*/
fos.close();
}
}
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
# 字节流写数据的两个问题
- 字节流写数据如何实现换行
- windows:
\r\n
- linux:
\n
- mac:
\r
- 系统通用:
String newLine = System.getProperty("line.separator"); out.write(newLine.getBytes())
- windows:
- 字节流写数据如何实现追加写入
public FileOutputStream(String name, boolean append)
- 创建文件输出流以指定的名称写入文件。如果第二个参数为
true
,则字节将写入文件的末尾而不是开头
示例代码3:
package com.itheima.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 字节流输入实现:
* 1. 换行
* 2. 追加输出
*
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileOutputStreamDemo3 {
public static void main(String[] args) throws IOException {
/**
* 1. 创建字节输出流对象
* 注意:
* 1. 如果文件不存在,会帮我们自动创建
* 2. 如果文件已存在,会把文件内容清空
*/
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "fos_demo3.txt"; // 指定字节输出流对象
FileOutputStream fos = new FileOutputStream(filePath);
/**
* Windows环境下实现换行输出的方式
* 1. \r\n
* 2. System.getProperty("line.spearator")
*/
String newLine = System.getProperty("line.spearator");
for (int i = 0; i < 10; i++) {
String content = "Hello " + i;
fos.write(content.getBytes());
fos.write("\r\n".getBytes());
}
String end = "文件结束";
fos.write(end.getBytes());
/**
* 3. 释放资源
*/
fos.close();
}
}
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
# 字节流写数据添加异常处理
- 异常处理格式:
try-catch-finally
try {
可能出现异常的代码;
} catch(异常类名 变量名) {
异常的处理代码;
} finally {
执行所有释放资源操作;
}
2
3
4
5
6
7
finally
特点:被finally
控制的语句一定会执行,除非JVM退出
示例代码4:
package com.itheima.io;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 字节流写数据添加异常处理代码
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileOutputStreamDemo4 {
public static void main(String[] args) {
/**
* 1. 创建字节输出流对象
* 注意:
* 1. 如果文件不存在,会帮我们自动创建
* 2. 如果文件已存在,会把文件内容清空
*/
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "fos_demo4.txt"; // 指定字节输出流对象
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filePath);
/**
* 2. 写数据
*/
String content = "hello";
fos.write(content.getBytes());
} catch (IOException e) {
// 处理异常
e.printStackTrace();
} finally {
// 3. 释放资源
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
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
# 字节流读数据(一次读一个字节数据)
- 字节输入流
FileInputStream(String name)
:通过打开与实际文件的连接来创建一个FileInputStream
,该文件由文件系统中的路径名命名
- 字节输入流读取数据的步骤
- 创建字节输入流对象
- 调用字节输入流对象的读数据方法
- 释放资源
示例代码5:
package com.itheima.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 字节输入流示例代码1
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileInputStreamDemo1 {
public static void main(String[] args) {
// 文件路径
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "fis_demo1.txt";
FileInputStream fis = null;
try {
// 1. 创建字节输入流对象
fis = new FileInputStream(filePath);
int byteData;
/**
* 2. 按字节读取数据
* fis.read(): 读数据
* byteData = fis.read(): 把读取到的数值赋值给byteData
* byteData == -1时,读取文件结束
*/
while ((byteData = fis.read()) != -1) {
System.out.println((char) byteData);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
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
# 字节流复制文件
案例需求:把D:\itcast\Temp\io\in\fis_demo2.txt
文件内容复制到D:\itcast\Temp\io\out\
目录下。
实现步骤:
- 复制文本文件,其实就把文本文件的内容从一个文件中读取出来,然后写入到另一个文件中
- 使用
FileInputStream
读取源文件:D:\itcast\Temp\io\in\fis_demo2.txt
- 使用
FileOutputStream
写入目标文件:D:\itcast\Temp\io\out\fis_demo2.txt
,文件名可以任意命名
示例代码6:
package com.itheima.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 通过字节输入流、输出流复制文件
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileInputStreamDemo2 {
public static void main(String[] args) {
// 源文件路径
String sourcePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "in"
+ File.separator + "fis_demo2.txt";
// 目标文件路径
String targetPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "out"
+ File.separator + "fis_demo2.txt";
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 1. 根据数据源创建字节输入流对象
fis = new FileInputStream(sourcePath);
// 1. 根据目的地创建字节输出流对象
fos = new FileOutputStream(targetPath);
// 2. 读数据,写数据,复制文本文件(一次读取一个字节,一次写入一个字节)
int byteData;
while ((byteData = fis.read()) != -1) {
fos.write(byteData);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
if (fis != null && fos != null) {
try {
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
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
# 字节流读取数据(一次读取一个字节数组数据)
- 一次读取一个字节数组的方法
public int read(byte[] b)
:从输入流读取最多b.length
个字节的数据- 返回的是读入缓冲区的总字节数,也就是实际读取到的字节个数
示例代码7:
package com.itheima.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* 字节流读取数据一次读取一个字节数组的数据
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileInputStreamDemo3 {
public static void main(String[] args) {
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "fis_demo3.txt";
FileInputStream fis = null;
try {
// 1. 创建字节输入流对象
fis = new FileInputStream(filePath);
// 2. 定义字节数组,读取数据
byte[] bs = new byte[1024]; // 一般为1024及其整数倍
int len;
// 循环读取
while ((len = fis.read(bs)) != -1) {
System.out.println(new String(bs, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
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
# 字节流复制文件
案例需求:
实现步骤:
- 根据源文件创建字节输入流对象
- 根据目的地址创建字节输出流对象
- 读写数据,复制图片(一次读取一个字节数组,一次写入一个字节数组)
- 释放资源
示例代码8:
package com.itheima.io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 通过字节流复制文件,一次读取一个字节数组,一次写入一个字节数组
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class FileInputStreamDemo4 {
public static void main(String[] args) {
// 源文件路径
String sourcePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "in"
+ File.separator + "itcast.png";
// 目标文件路径
String targetPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "out"
+ File.separator + "copy.png";
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 1. 根据源文件创建字节输入流对象
fis = new FileInputStream(sourcePath);
// 1. 根据目的地创建字节输出流对象
fos = new FileOutputStream(targetPath);
// 2. 读写数据,复制图片,一次读取一个字节数组,一次写入一个字节数组
byte[] bs = new byte[1024];
int len;
while ((len = fis.read(bs)) != -1) {
fos.write(bs, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 3. 释放资源
if (fis != null && fos != null) {
try {
fis.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
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
# 字节缓冲流
# 字节缓冲流构造方法
字节缓冲流 介绍
BufferOutputStream
:该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节调用底层系统的功能。BufferedInputStream
:创建一个内部缓冲区数组,当从流中读取字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次操作很多个字节。
构造方法:
|方法名|说明|
|BufferedOutputStream(OutputStream out)
|创建字节缓冲输出流对象|
|BufferedInputStream(InputStream in)
|创建字节缓冲输入流对象|
示例代码9:
package com.itheima.io;
import java.io.*;
/**
* 字节缓冲流示例代码
*
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class BufferedStreamDemo1 {
public static void main(String[] args) throws IOException {
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "bos_demo1.txt";
// 字节缓冲输出流
FileOutputStream fos = new FileOutputStream(filePath);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 写数据
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
// 释放资源
bos.close();
// 字节缓冲输入流
FileInputStream fis = new FileInputStream(filePath);
BufferedInputStream bis = new BufferedInputStream(fis);
// 一次读取一个字节数组数据
byte[] bs = new byte[1024];
int len;
while ((len = bis.read(bs)) != -1) {
System.out.println(new String(bs, 0, len));
}
// 释放资源
bis.close();
}
}
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
# 字节缓冲流复制视频
案例需求:
实现步骤:
- 根据源视频文件创建字节输入流对象
- 根据目标文件创建字节输出流对象
- 读写数据,复制视频
- 释放资源
代码实现:
package com.itheima.io;
import java.io.*;
/**
* 字节缓冲流拷贝视频
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class BufferedCopyDemo {
public static void main(String[] args) throws IOException {
// 源视频文件路径
String sourcePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "in"
+ File.separator + "嘿嘿嘿.avi";
// 目标视频文件路径
String targetPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "out"
+ File.separator + "哈哈哈.avi";
// 创建字节缓冲输入流对象
FileInputStream fis = new FileInputStream(sourcePath);
BufferedInputStream bis = new BufferedInputStream(fis);
// 创建字节缓冲输出流对象
FileOutputStream fos = new FileOutputStream(targetPath);
BufferedOutputStream bos = new BufferedOutputStream(fos);
// 拷贝文件
byte[] bs = new byte[1024];
int len;
while ((len = bis.read(bs)) != -1) {
bos.write(bs, 0, len);
}
// 释放资源
bos.close();
bis.close();
}
}
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
# 字符流
# 为什么需要字符流
- 字符流介绍:由于字节流操作中文不是特别方便,所以Java就提供字符流,
字符流 = 字节流 + 编码表
- 中文的字节存储方式:用字节流复制文本文件时,文本文件也会有中文,但是这是没有问题的,原因是最终底层操作会自动进行字节拼接成中文,那么操作系统是如何识别成中文的呢?原因是汉子在存储的时候,无论选择哪种编码存储,第一个字节都是负数。
# 编码表
- 什么是字符集
字符集是一个系统支持的所有字符的集合,包括各国文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然有至少一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集等
常见的字符集
- ASCII字符集:是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号) 基本的ASCII字符集,使用7位表示一个字符,供128字符。ASCII的扩展字符集使用8位表示一个字符,供256个字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国文字、标点符号、图形符号、数字等
GBXXX字符集:
- GBK:最常用的中文码表。是在GB2312表中基础上的扩展规范,使用双字节编码方案,共收录了21003个汉子,完全兼容GB2312标准,同时支持繁体汉子以及日韩汉字等。
Unicode字符集:
- UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字符编码
- 编码规则:128个US-ASCII字符,只需一个字节编码拉丁文等字符,需要二个字节编码大部分常用字(含中文),使用三个字节编码其他极少使用的Unicode辅助字符,使用四字节编码
# 字符串中的编码解码问题
- 相关方法
方法名 | 说明 |
---|---|
byte[] getBytes() | 使用平台的默认字符集将该String 编码为一系列字节 |
byte[] getBytes(String charsetName) | 使用指定的字符集将该String 编码为一系列字节 |
String(byte[] bytes) | 使用平台的默认字符集解码指定的字节数组来创建字符串 |
String(byte[] bytes, String charsetName) | 通过指定的字符集编码指定的字节数组来创建字符串 |
代码示例:
package com.itheima.io;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
* 字符集示例代码
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class CharsetDemo1 {
public static void main(String[] args) throws UnsupportedEncodingException {
// 定义一个字符串
String str = "中国";
byte[] bys = str.getBytes("GBK");
System.out.println(Arrays.toString(bys));
String str2 = new String(bys, "GBK");
System.out.println(str2);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 字符流写数据
介绍:
Writer
:用于写入字符流的抽象父类FileWriter
:用于写入字符流的常用子类
构造方法
方法名 | 说明 |
---|---|
FileWriter(File file) | 根据给定的File 对象构造一个FileWriter 对象 |
FileWriter(File file, boolean append) | 根据给定的File 对象构造一个FileWriter 对象 |
FileWriter(String fileName) | 根据给定的文件名构造一个FileWriter 对象 |
FileWriter(String fileName, boolean append) | 根据给定的文件名以及指示是否附加写入数据的boolean 值来构造FileWriter 对象 |
- 成员方法
方法名 | 说明 |
---|---|
void write(int c) | 写一个字符 |
void write(char[] cbuf) | 写入一个字符数组 |
void write(char[] cbuf, int off, int len) | 写入字符数组的一部分 |
void write(String str) | 写一个字符串 |
void write(String str, int off, int len) | 写一个字符串的一部分 |
- 刷新和关闭的方法
方法名 | 说明 |
---|---|
flush() | 刷新流,之后还可以继续写数据 |
close() | 关闭流,释放资源,但是在关闭之前会先刷新流。一旦关闭,就不能再写数据 |
代码演示:
package com.itheima.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
* 字符输出流示例
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class WriterDemo1 {
public static void main(String[] args) throws IOException {
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "writer_demo1.txt";
FileWriter fw = new FileWriter(filePath);
// void write(int c): 写一个字符
// fw.write(97);
// fw.write(98);
// fw.write(99);
// void write(char[] cbuf): 吸入一个字符数组
// char[] chs = { 'a', 'b', 'c', 'd', 'e'};
// fw.write(chs);
// void write(char[] cbuf, int off, int len): 写入字符数组的一部分
// fw.write(chs, 0, chs.length);
// fw.write(chs, 1, 3);
// void write(String str): 写一个字符串
// fw.write("abcde");
// void write(String str, int off, int len): 写一个字符串的一部分
// fw.write("abcde", 0, "abcde".length());
fw.write("abcde", 1, 3);
// 释放资源
fw.close();
}
}
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
# 字符流读数据
介绍
Reader
:用于读取字符流的抽象父类FileReader
:用于读取字符流的常用子类
构造方法
方法名 | 说明 |
---|---|
FileReader(File file) | 在给定读取数据的File 的情况下创建一个FileReader |
FileReader(String fileName) | 在给定读取数据的文件名的情况下创建一个FileReader |
- 成员方法
|方法名|说明|
|int read()
|一次读一个字符数据|
|int read(char[] cbuf)
|一次读一个字符数组数据|
代码示例:
package com.itheima.io;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* 字符输入流代码示例
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class ReaderDemo1 {
public static void main(String[] args) throws IOException {
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "reader_demo1.txt";
FileReader fr = new FileReader(filePath);
// 一次读一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1) {
System.out.println(new String(chs, 0, len));
}
// 释放资源
fr.close();
}
}
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
# 字符流用户注册案例
案例:将键盘录入的用户名和密码保存到本地实现永久化存储
实现步骤:
- 获取用户输入的用户名和密码
- 将用户输入的用户名和密码写入到本地文件中
- 关闭流、释放资源
代码实现:
package com.itheima.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
/**
* 案例需求:持久化保存用户输入的用户名和密码
*
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class WriterDemo2 {
public static void main(String[] args) throws IOException {
/**
* 需求:将键盘录入的用户名和密码保存到本地文件
* 要求:用户名独占一行,密码独占一行
* 分析:
* 1. 实现键盘录入,获取用户名和密码
*/
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = sc.next();
System.out.println("请输入密码:");
String password = sc.next();
// 2. 分别把用户名和密码写到本地文件
String filePath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "login.txt";
FileWriter fw = new FileWriter(filePath);
// 将用户名和密码写到文件中
fw.write(username);
// 表示回车换行符
// Windows: \r\n
// Linux: \n
// MacOS: \r
fw.write("\r\n");
fw.write(password);
// 刷新流
fw.flush();
// 3. 释放资源
fw.close();
}
}
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
# 字符缓冲流
字符缓冲流介绍
BufferedWriter
:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,以提供单个字符,或者可以接受默认大小。默认值足够大,可用于大多数用途BufferedReader
:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途
构造方法
方法名 | 说明 |
---|---|
BufferedWriter(Writer out) | 创建字符缓冲输出流对象 |
BufferedReader(Reader in) | 创建字符缓冲输入流对象 |
代码演示:
package com.itheima.io;
import java.io.*;
/**
* 字符缓冲流应用代码示例
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class BufferedWriterReaderDemo {
public static void main(String[] args) throws IOException {
String writerPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "writer_demo2.txt";
String readerPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "reader_demo2.txt";
FileWriter fw = new FileWriter(writerPath);
BufferedWriter bw = new BufferedWriter(fw);
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();
FileReader fr = new FileReader(readerPath);
BufferedReader br = new BufferedReader(fr);
// 一次读取一个字符数组数据
char[] chs = new char[1024];
int len;
while ((len = br.read(chs)) != -1) {
System.out.println(new String(chs, 0, len));
}
br.close();
}
}
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
# 字符缓冲流特有功能
- 方法介绍:
BufferedWriter
方法名 | 说明 |
---|---|
void newLine() | 写一行分割符,行分割符字符串由系统属性定义 |
- 方法介绍:
BufferedReader
方法名 | 说明 |
---|---|
String readLine() | 读一行文字。结果包含一行的内容,但不包括行终止字符,如果流的结尾已经到达,则为null |
代码示例:
package com.itheima.io;
import java.io.*;
/**
* 字符缓冲流特有功能应用代码
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class BufferedWriterReaderDemo1 {
public static void main(String[] args) throws IOException {
String writerPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "writer_demo3.txt";
String readerPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "reader_demo3.txt";
FileWriter fw = new FileWriter(writerPath);
BufferedWriter bw = new BufferedWriter(fw);
for(int i = 0; i < 10; i++) {
bw.write("hello " + i);
bw.newLine();
bw.flush();
}
bw.close();
FileReader fr = new FileReader(readerPath);
BufferedReader br = new BufferedReader(fr);
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}
}
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
# 字符缓冲流操作文件中数据排序案例
- 案例需求
使用字符缓冲流读取文件中的数据,排序后再次写到本地文件
实现步骤
- 将文件中的数据读取到程序中
- 对读取的数据进行处理
- 将处理后的数据添加到集合中
- 对集合中的数据进行排序
- 将排序后的集合中的数据写入到文件中
代码实现
package com.itheima.io;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* 对文件中的数值进行排序示例
* @author sunyy
* @version 0.0.1
* @since 2022.10.29
*/
public class SortDemo {
public static void main(String[] args) throws IOException {
String unorderPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "sort_unorder.txt";
String orderPath = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "sort_order.txt";
FileWriter fw = new FileWriter(unorderPath);
BufferedWriter bw = new BufferedWriter(fw);
Random random = new Random();
for(int i = 0; i < 10; i++) {
int num = random.nextInt(100);
bw.write(num + "");
bw.newLine();
}
bw.close();
FileReader fr = new FileReader(unorderPath);
BufferedReader br = new BufferedReader(fr);
String line = null;
List<Integer> datas = new ArrayList<>();
while ((line = br.readLine()) != null) {
System.out.println("读取的数字:" + line);
int num = Integer.parseInt(line);
datas.add(num);
}
br.close();
System.out.println("读取到的所有数据:" + datas.toString());
Collections.sort(datas);
System.out.println("排序后的数据:" + datas.toString());
// 把排序后的结果写会本地文件
FileWriter fw2 = new FileWriter(orderPath);
BufferedWriter bw2 = new BufferedWriter(fw2);
for (Integer num : datas) {
bw2.write(num + " ");
bw2.flush();
}
bw2.close();
}
}
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
# IO 流小结
# 对象操作流
# 对象序列化流
介绍:
- 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象
- 这种机制就是使用一个字节序列表示一个对象,该字节序列包含:对象的类型、对象的数据和对象中存储的属性等信息
- 字节序列写到文件之后,相当于文件中持久保存了一个对象的信息
- 反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化
对象序列化流:
ObjectOutputStream
- 将对象的原始数据类型和图形写入
OutputStream
。可以使用ObjectInputStream
读取对象。可以通过流来实现对象的持久化存储。如果流是网络套接字流,则可以在另一个主机上或另一个进程中重构对象
- 将对象的原始数据类型和图形写入
构造方法:
方法名 | 说明 |
---|---|
ObjectOutputStream(OutputStream out) | 依据OutputStream 创建一个写入ObjectOutputStream |
- 学历恶化对象的方法:
方法名 | 说明 |
---|---|
void writeObject(Object obj) | 将指定的对象写入ObjectOutputStream |
- 示例代码:
package com.itheima.serialize;
import java.io.Serializable;
/**
* 学生类
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class Student implements Serializable {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 构造方法
* @param name
* @param age
*/
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
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
package com.itheima.serialize;
import java.io.*;
/**
* 对象序列化示例代码
*
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class ObjectSerializeDemo1 {
public static void main(String[] args) throws IOException {
// 1. 依据OutputStream创建一个ObjectOutputStream
String path = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "oos"
+ File.separator + "student.txt"; // 指定字节输出流对象
FileOutputStream fos = new FileOutputStream(path);
ObjectOutputStream oos = new ObjectOutputStream(fos);
// 2. 创建学生对象
Student stu = new Student("张三", 30);
// 3. 调用 void writeObject(Object obj) 将指定的对象写入ObjectOutputStream
oos.writeObject(stu);
// 4. 释放资源
oos.close();
}
}
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
注意事项
- 一个对象要想被序列化,该对象所属的类必须实现
Serializable
接口 Serializable
是一个标记接口,实现该接口,不需要重写任何方法
# 对象反序列化流
对象反序列化流:
ObjectInputStream
ObjectInputStream
反序列化上面ObjectOutputStream
序列化的对象数据
构造方法:
|方法名|说明|
|ObjectInputStream(InputStream in)
|依据InputStream
创建读取对象的ObjectInputStream
|
- 反序列化对象的方法
方法名 | 说明 |
---|---|
Object readObject() | 从ObjectInputStream 读取一个对象 |
- 示例代码
package com.itheima.serialize;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* 对象反序列化代码示例
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class ObjectSerializeDemo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 依据InputStream创建一个ObjectInputStream
String path = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "oos"
+ File.separator + "student.txt";
FileInputStream fis = new FileInputStream(path);
ObjectInputStream ois = new ObjectInputStream(fis);
// 2. 使用 Object readObject() 从 ObjectInputStream 读取一个对象
Object obj = ois.readObject();
Student stu = (Student) obj;
System.out.println(stu);
// 3. 释放资源
ois.close();
}
}
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
# serialVersionUID 和 transient
serialVersionUID:
- 用对象序列化流序列化一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出现问题?
- 会抛出
InvalidClassException
异常
- 会抛出
- 如何解决?
- 重新序列化
- 给对象所属的类加一个属性
serialVersionUID
private static final long serialVersionUID = 42L;
- 用对象序列化流序列化一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出现问题?
transient:
- 如果一个对象中的某个成员变量的值不想被序列化,又改如何实现呢?
- 给该成员变量加
transient
关键字修饰,该关键字标记的成员变量不参与序列化过程
- 给该成员变量加
- 如果一个对象中的某个成员变量的值不想被序列化,又改如何实现呢?
示例代码:
package com.itheima.serialize;
import java.io.Serializable;
/**
* 学生类
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class Student implements Serializable {
private static final long serialVersionUID = 42L;
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private transient int age;
/**
* 构造方法
* @param name
* @param age
*/
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
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
package com.itheima.serialize;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
/**
* 对象反序列化代码示例
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class ObjectSerializeDemo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 1. 依据InputStream创建一个ObjectInputStream
String path = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "oos"
+ File.separator + "student.txt";
FileInputStream fis = new FileInputStream(path);
ObjectInputStream ois = new ObjectInputStream(fis);
// 2. 使用 Object readObject() 从 ObjectInputStream 读取一个对象
Object obj = ois.readObject();
Student stu = (Student) obj;
System.out.println(stu);
// 3. 释放资源
ois.close();
}
}
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
# 对象操作流练习
案例需求:创建多个学生类对象写到文件中,并再次读取到内存中
实现步骤:
- 创建序列化流对象
- 创建多个学生对象
- 将学生对象添加的集合中
- 将集合对象序列化到文件中
- 创建反序列化流对象
- 将文件中的对象数据,读取到内存中
代码实现:练习作业
# Properties 集合
# Properties 作为 Map 集合的使用
Properties
介绍:- 是一个
Map
体系的集合类 Properties
可以保存到流中或从流中加载- 属性列表中的每个键及其对应的值都是一个字符串
- 是一个
Properties
基本使用
package com.itheima.prop;
import java.util.Properties;
import java.util.Set;
/**
* Properties简单使用
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class PropertiesDemo1 {
public static void main(String[] args) {
// 1. 创建Properties集合对象
Properties prop = new Properties();
// 2. 初始化集合元素
prop.put("student01", "张三");
prop.put("student02", "李四");
prop.put("student03", "王五");
// 3. 遍历集合
Set<Object> keySet = prop.keySet();
for (Object key : keySet) {
Object value = prop.get(key);
System.out.println(key + "," + value);
}
}
}
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
# Properties 作为 Map 集合的特有方法
- 特有方法
方法名 | 说明 |
---|---|
Object setProperty(String key, String value) | 设置集合的键和值,都是String 类型,底层调用Hashtable 方法put |
String getProperty(String key) | 使用此属性列表中指定的键搜索属性 |
Set<String> stringPropertyNames() | 从该属性列表中返回一个不可修改的键集合,其中键及其对应的值是字符串 |
- 示例代码
package com.itheima.prop;
import java.util.Properties;
import java.util.Set;
/**
* Properties简单使用
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class PropertiesDemo1 {
public static void main(String[] args) {
// 1. 创建Properties集合对象
Properties prop = new Properties();
// 2. 初始化集合元素
prop.put("student01", "张三");
prop.put("student02", "李四");
prop.put("student03", "王五");
// 3. 遍历集合
Set<Object> keySet = prop.keySet();
for (Object key : keySet) {
Object value = prop.get(key);
System.out.println(key + "," + value);
}
// 4. 方式二遍历
Set<String> names = prop.stringPropertyNames();
for (String key : names) {
String value = prop.getProperty(key);
System.out.println(key + "," + value);
}
}
}
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
# Properties和IO流相结合的方法
- 与IO流结合
方法名 | 说明 |
---|---|
void load(Reader reader) | 从输入字符流读取属性列表(键和元素对) |
void store(Writer writer, String comments) | 将此属性列表(键和元素对)写入此Properties 表中,以适合使用load(Reader) 方法的格式写入输出字符流 |
- 示例代码
package com.itheima.prop;
import java.io.*;
import java.util.Properties;
import java.util.Set;
/**
* Properties与IO流结合
*
* @author sunyy
* @version 0.0.1
* @since 2022.10.30
*/
public class PropertiesDemo2 {
public static void main(String[] args) throws IOException {
String path = "D:" + File.separator + "itcast"
+ File.separator + "Temp"
+ File.separator + "io"
+ File.separator + "oos"
+ File.separator + "student.txt";
// 将集合中的数据保存到文件
storeData(path);
// 将文件中的数据加载到集合
loadData(path);
}
/**
* 保存数据
* @param path
* @throws IOException
*/
private static void storeData(String path) throws IOException {
// 1. 创建Properties对象
Properties prop = new Properties();
// 2. 初始化集合元素
prop.put("student01", "张三");
prop.put("student02", "李四");
prop.put("student03", "王五");
// 3. 创建输出流
FileWriter fw = new FileWriter(path);
prop.store(fw, null);
fw.close();
}
/**
* 加载数据
* @param path
* @throws IOException
*/
private static void loadData(String path) throws IOException {
// 1. 创建Properties对象
Properties prop = new Properties();
// 2. 创建输入流
FileReader fr = new FileReader(path);
// 3. 加载数据,并释放资源
prop.load(fr);
fr.close();
// 4. 遍历
Set<String> keys = prop.stringPropertyNames();
for (String key : keys) {
String value = prop.getProperty(key);
System.out.println(key + "," + value);
}
}
}
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
- IO流概述和分类(理解)
- IO流介绍
- IO流的分类
- IO流的使用场景
- 文件操作类
- 创建和删除文件
- 创建和删除目录
- 遍历目录
- 字节流
- 字节流写数据的三种方式
- 字节流写数据的两个问题
- 字节流写数据添加异常处理
- 字节流读数据(一次读一个字节数据)
- 字节流复制文件
- 字节流读取数据(一次读取一个字节数组数据)
- 字节流复制文件
- 字节缓冲流
- 字节缓冲流构造方法
- 字节缓冲流复制视频
- 字符流
- 为什么需要字符流
- 编码表
- 字符串中的编码解码问题
- 字符流写数据
- 字符流读数据
- 字符流用户注册案例
- 字符缓冲流
- 字符缓冲流特有功能
- 字符缓冲流操作文件中数据排序案例
- IO 流小结
- 对象操作流
- 对象序列化流
- 对象反序列化流
- serialVersionUID 和 transient
- 对象操作流练习
- Properties 集合
- Properties 作为 Map 集合的使用
- Properties 作为 Map 集合的特有方法
- Properties和IO流相结合的方法