字节流
# 字节流
# 1. 字节输出流
字节输出流的作用是将程序中的数据以字节的形式输出到目标位置,如文件、网络连接、内存等。它主要用于处理二进制数据(如图片、音频、视频)或需要以字节为单位写入的其他数据。在 Java 中,字节输出流基于 OutputStream
抽象类,提供了一套标准的写出操作方法。
字节输出流的应用场景
- 文件写入: 字节输出流广泛应用于将数据写入文件。常见的实现类是
FileOutputStream
,它可以将程序中的数据写入磁盘上的文件,适用于保存二进制文件(如图片、视频)和文本文件。- 示例:保存用户输入的数据、日志文件、生成的配置文件等。
- 网络通信: 在网络编程中,字节输出流用于通过网络发送数据。比如通过
Socket
类的输出流将数据发送到远程服务器,通常用于传输二进制数据或字符数据。- 示例:发送文件数据、图片、音频流等。
- 数据处理: 字节输出流可以用于处理大块的二进制数据,如对图片、音频、视频等文件进行读写操作。
- 示例:将一段音频数据写入到文件,或将二进制图片数据传输到其他系统。
- 设备控制: 在一些硬件交互场景中,字节输出流可以用于将数据发送到特定设备,例如串口通信、I/O设备控制。
- 示例:控制打印机、串口设备的输出。
# 1. 字节输出流入门
FileOutputStream类 :
OutputStream
有很多子类,我们从最简单的一个子类开始。java.io.FileOutputStream
类是文件输出流,用于将数据写出到文件
字节输出流OutputStream主要方法:
write(int b)
:将一个字节写入输出流中,b
是要写入的字节数据(0~255 的整数)。write(byte[] b)
:将b.length
个字节从指定的字节数组写入此输出流中。write(byte[] b, int off, int len)
:将字节数组b
中,从起始位置off
开始,长度为len
个字节的数据写入输出流中close()
:关闭此输出流并释放与此流相关联的任何系统资源。
操作步骤:
- 创建字节输出流对象:实例化
FileOutputStream
对象。如果指定的文件不存在,Java 会自动创建该文件。如果文件已存在,默认情况下其内容会被清空(除非在构造函数中指定追加模式)。 - 写入数据:使用
write(int b)
方法写入单个字节,或使用write(byte[] b)
写入字节数组。数据写入后将以字节形式存储在文件中。 - 释放资源:使用完文件输出流后,调用
close()
方法关闭流,释放与流相关联的系统资源。忘记关闭流可能导致资源泄露。
- 创建字节输出流对象:实例化
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamExample {
public static void main(String[] args) throws IOException {
// Step 1: 创建字节输出流对象
// 如果指定路径的文件不存在,FileOutputStream 会自动创建这个文件(目录不存在不会自动创建)
// 如果文件已经存在,则其原有内容会被清空(除非以追加模式创建FileOutputStream)
FileOutputStream fos = new FileOutputStream("e:/test.txt");
// Step 2: 写数据
// 使用 write 方法将数据写入到文件中
// 这里的参数是要写入的字节,所以写入的是 ASCII 码对应的字符 'a'、'b' 和 'c'
fos.write(97); // 写入字节97,即字符 'a'
fos.write(98); // 写入字节98,即字符 'b'
fos.write(99); // 写入字节99,即字符 'c'
// 注意:文件中存储的是字节数据,如果打开文件查看,看到的是这些字节对应的字符
// Step 3: 释放资源
// 关闭文件输出流,释放与这个流相关联的系统资源
// 不调用 close 方法可能会导致资源泄露
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
# 2. 字节输出流写数据的方法
在 Java 中,FileOutputStream
是常用的字节输出流类,主要用于将数据写入文件。字节输出流的操作方法分为写入单个字节、写入字节数组、部分写入字节数组。
- 写单个字节:
write(int b)
方法,一次写入一个字节。 - 写字节数组:
write(byte[] b)
方法,一次写入整个字节数组。 - 部分写字节数组:
write(byte[] b, int off, int len)
方法,从字节数组的指定位置开始,写入指定长度的数据。
# 1. 写单个字节:write(int b)
方法功能:
将一个字节写入文件,参数 b
是要写入的字节(0~255)。
常见应用场景:
逐字节写入数据,如写入字符的 ASCII 码。
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 演示如何使用 write(int b) 方法逐字节写入数据到文件中。
*/
public class FileOutputStreamSingleByteDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 创建 FileOutputStream 对象,准备向指定文件写入数据
// 第二个参数 true 表示以追加形式写文件
fos = new FileOutputStream("e:/singleByteOutput.txt", true);
// 写入单个字节,写入的是 ASCII 码为 97 的字符 'a'
fos.write(97);
// 写入其他字节
fos.write(98); // ASCII 码 98 -> 'b'
fos.write(99); // ASCII 码 99 -> 'c'
// 刷新输出流,确保数据写入文件
fos.flush();
System.out.println("单个字节写入完成。");
} catch (IOException e) {
// 捕获并处理可能的 IO 异常
System.err.println("写入文件时发生错误:" + e.getMessage());
} finally {
// 关闭流,释放资源
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
输出效果:
在 e:/singleByteOutput.txt
文件中看到如下内容:
abc
# 2. 写入字节数组:write(byte[] b)
方法功能:
将整个字节数组 b
写入文件。
常见应用场景:
一次性将一段数据(如字符串、二进制内容)写入文件。
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 演示如何使用 write(byte[] b) 方法将整个字节数组写入文件。
*/
public class FileOutputStreamByteArrayDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 创建 FileOutputStream 对象,准备向指定文件写入数据
fos = new FileOutputStream("e:/byteArrayOutput.txt", true);
// 将字符串转换为字节数组
String str = "Hello, Scholar!";
byte[] strBytes = str.getBytes();
// 将整个字节数组写入文件
fos.write(strBytes);
// 刷新输出流,确保数据写入文件
fos.flush();
System.out.println("字节数组写入完成。");
} catch (IOException e) {
// 捕获并处理可能的 IO 异常
System.err.println("写入文件时发生错误:" + e.getMessage());
} finally {
// 关闭流,释放资源
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
输出效果:
在 e:/byteArrayOutput.txt
文件中看到如下内容:
Hello, Scholar!
# 3. 部分写入字节数组:write(byte[] b, int off, int len)
方法功能:
从字节数组 b
中,从偏移量 off
开始,写入长度为 len
的字节到文件。
常见应用场景:
需要写入字节数组的部分数据时,如只写入字符串的一部分或跳过不需要的部分。
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 演示如何使用 write(byte[] b, int off, int len) 方法部分写入字节数组数据。
*/
public class FileOutputStreamPartialByteArrayDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 创建 FileOutputStream 对象,准备向指定文件写入数据
fos = new FileOutputStream("e:/partialByteArrayOutput.txt", true);
// 将字符串转换为字节数组
String str = "Hello, Scholar!";
byte[] strBytes = str.getBytes();
// 写入字节数组中的部分数据,从偏移量 7 开始,写入 8 个字节
// 这将写入 "Scholar" 部分
fos.write(strBytes, 7, 8);
// 刷新输出流,确保数据写入文件
fos.flush();
System.out.println("部分字节数组写入完成。");
} catch (IOException e) {
// 捕获并处理可能的 IO 异常
System.err.println("写入文件时发生错误:" + e.getMessage());
} finally {
// 关闭流,释放资源
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
输出效果:
在 e:/partialByteArrayOutput.txt
文件中看到如下内容:
Scholar
# 3. 写数据的换行和追加写入
在 Java 的字节输出流中,写入数据时经常需要处理换行和追加写入。
# 1. 写数据并覆盖原有内容
当你使用 FileOutputStream
时,如果不指定追加模式,新数据会覆盖原有文件内容。下面是一个该示例将展示如何在文件中写入数据并进行换行操作。
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 示范使用 FileOutputStream 进行文件写入时实现换行的操作。
*/
public class FileOutputStreamOverwriteDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 创建 FileOutputStream 对象,未启用追加模式(默认),每次运行将覆盖原文件内容
fos = new FileOutputStream("e:/overwriteOutput.txt");
// 写入单个字节数据,这里写入的 ASCII 码 97 对应字符 'a'
fos.write(97);
// 写入换行符,使用系统特定的换行符(Windows: "\r\n")
fos.write("\r\n".getBytes());
// 继续写入其他数据并进行换行
fos.write(98); // 'b'
fos.write("\r\n".getBytes());
fos.write(99); // 'c'
fos.write("\r\n".getBytes());
// 数据写入完毕后,刷新输出流
fos.flush();
System.out.println("数据已写入并覆盖原文件内容。");
} catch (IOException e) {
// 处理可能的 IO 异常
System.err.println("文件写入时发生错误:" + e.getMessage());
} finally {
// 关闭流,释放资源
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
输出效果:
每次运行代码时,文件 e:/overwriteOutput.txt
中的内容会被新的数据覆盖,内容如下:
a
b
c
2
3
# 2. 写数据并追加到文件末尾
如果你希望新写入的内容追加到已有文件内容的末尾,而不是覆盖原内容,需要启用追加模式。追加模式通过构造方法中的第二个参数来设置。
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 示范使用 FileOutputStream 进行追加写入的操作。
*/
public class FileOutputStreamAppendDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 创建 FileOutputStream 对象,启用追加模式
fos = new FileOutputStream("e:/appendOutput.txt", true);
// 写入单个字节数据,并进行换行操作
fos.write(97); // 'a'
fos.write("\r\n".getBytes());
fos.write(98); // 'b'
fos.write("\r\n".getBytes());
fos.write(99); // 'c'
fos.write("\r\n".getBytes());
// 数据写入完毕后,刷新输出流
fos.flush();
System.out.println("数据已追加写入文件末尾。");
} catch (IOException e) {
// 处理可能的 IO 异常
System.err.println("文件写入时发生错误:" + e.getMessage());
} finally {
// 关闭流,释放资源
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
输出效果:
文件 e:/appendOutput.txt
中的内容会随着每次运行代码不断追加,如下:
a
b
c
a
b
c
2
3
4
5
6
# 3. 使用换行符处理不同操作系统
不同操作系统的换行符可能不同,例如:
- Windows:
\r\n
- Linux:
\n
- macOS(旧版):
\r
为了保证跨平台的兼容性,可以在写入换行符时动态适配操作系统的换行符。
import java.io.FileOutputStream;
import java.io.IOException;
/**
* 示范如何根据操作系统动态处理换行符。
*/
public class FileOutputStreamCrossPlatformDemo {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
// 创建 FileOutputStream 对象,启用追加模式
fos = new FileOutputStream("e:/crossPlatformOutput.txt", true);
// 获取系统的换行符
String lineSeparator = System.getProperty("line.separator");
// 写入数据并动态适配系统换行符
fos.write("Line 1".getBytes());
fos.write(lineSeparator.getBytes());
fos.write("Line 2".getBytes());
fos.write(lineSeparator.getBytes());
fos.write("Line 3".getBytes());
fos.write(lineSeparator.getBytes());
// 数据写入完毕后,刷新输出流
fos.flush();
System.out.println("数据已根据操作系统换行符写入文件。");
} catch (IOException e) {
// 处理可能的 IO 异常
System.err.println("文件写入时发生错误:" + e.getMessage());
} finally {
// 关闭流,释放资源
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
输出效果:
文件 e:/crossPlatformOutput.txt
中的内容根据操作系统的换行符进行分行,如下(在 Windows 中):
Line 1
Line 2
Line 3
2
3
总结
- 写入单个字节并换行:使用
write(int b)
方法写入单个字节,并通过write("\r\n".getBytes())
进行换行。 - 追加写入:启用追加模式后,新的数据会添加到文件末尾,而不覆盖原内容。
- 跨平台换行符:动态获取系统换行符,确保程序在不同操作系统上表现一致。
# 2. 字节输入流
字节输入流的作用是将外部数据源中的数据以字节的形式读入程序。它主要用于读取二进制数据,如文件、网络数据流、图片、音频、视频等。在 Java 中,字节输入流基于 InputStream
抽象类,提供了一套标准的读取操作方法。
字节输入流的应用场景
- 文件读取: 字节输入流常用于从文件中读取数据,特别适合读取二进制文件,如图片、音频、视频文件等。常见的实现类是
FileInputStream
,它可以从文件中逐字节读取数据。- 示例:读取配置文件、加载图片文件、读取二进制数据等。
- 网络通信: 在网络编程中,字节输入流用于接收从网络传输的数据。例如,通过
Socket
类的输入流从远程服务器接收数据,适用于接收二进制数据或字符数据。- 示例:接收文件数据、图片、音频流等。
- 数据处理: 字节输入流可以用于处理和解析大块的二进制数据,适合从外部源读取复杂格式的数据流。
- 示例:读取和解析音频文件、视频文件,或从压缩文件中解压数据。
- 设备读取: 在一些硬件交互场景中,字节输入流可以用于从特定设备读取数据,例如从串口设备或其他输入设备获取数据。
- 示例:从传感器设备读取数据,从打印机接收状态信息等。
InputStream
类有很多的实现子类,下面列举了一些比较常用的:
详细说明一下上图中的类:
1.InputStream: InputStream是所有字节输入流的抽象基类,前面说过抽象类不能被实例化,实际上是作为模板而存在的,为所有实现类定义了处理输入流的方法。
2.Fi1eInputSream:文件输入流,一个非常重要的字节输入流,用于对文件进行读取操作。
3.PipedInputStream:管道字节输入流,能实现多线程间的管道通信。
4.ByteArrayInputStream:字节数组输入流,从字节数组(byte)中进行以字节为单位的读取,也就是将资源文件都以字节的形式存入到该类中的字节数组中去。
5.FilterInputStream:装饰者类,具体的装饰者继承该类,这些类都是处理类,作用是对节点类进行封装,实现一些特殊功能。
6.DataInputStream:数据输入流,它是用来装饰其它输入流,作用是"允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型。
7.BufferedInputStream:缓冲流,对节点流进行装饰,内部会有一个缓存区,用来存放字节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送,效率更高。
8.ObjectInputstream:对象输入流,用来提供对基本数据或对象的持久存储。通俗点说,也就是能直接传输对象,通常应用在反序列化中。它也是一种处理流,构造器的入参是一个InputStream的实例对象。
# 1.字节输入流入门
字节输入流类
- InputStream类 : 字节输入流最顶层的类 , 抽象类
- FileInputStream类 : FileInputStream extends InputStream
字节输入流
InputStream
主要方法:read()
:从输入流中读取一个字节的数据。当达到文件末尾时,返回-1。read(byte[] b)
:从输入流中读取b.length
个字节的数据并存储到字节数组b
中。read(byte[] b, int off, int len)
:从输入流中读取最多len
个字节的数据,将其存储在数组b
中,off
参数表示数组b
中的起始位置。close()
:关闭输入流并释放与该流相关联的所有资源。
操作步骤:
- 创建输入流对象:确定要读取的文件路径,并实例化一个
FileInputStream
对象。注意,如果文件不存在,将抛出FileNotFoundException
。 - 读取数据:使用
read()
方法从文件中逐字节读取数据。read()
方法每次调用返回一个字节的数据,并自动移动到下一个字节。当文件结束时,read()
方法返回-1
。 - 释放资源:完成数据读取后,应使用
close()
方法关闭流,以释放与流相关的系统资源。
- 创建输入流对象:确定要读取的文件路径,并实例化一个
代码示例:单字节读取
import java.io.FileInputStream;
import java.io.IOException;
/**
* 示例:使用 FileInputStream 读取单个字节的数据。
*/
public class FileInputStreamDemo1 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 创建字节输入流对象,指定要读取的文件路径
fis = new FileInputStream("E:/a.txt");
// 使用 read 方法读取文件中的一个字节
int byteData = fis.read(); // read 方法返回读取到的字节,如果达到文件末尾返回 -1
System.out.println("读取到的字节对应字符:" + (char) byteData); // 将读取到的字节转换为字符打印
} catch (IOException e) {
e.printStackTrace();
} finally {
// 完成读取操作后关闭输入流,释放资源
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
# 2. 每次读取一个字节 (逐字节读取)
- 创建
FileInputStream
对象:指定需要读取的文件路径,创建一个FileInputStream
实例。 - 读取数据:通过循环调用
read()
方法,从文件中连续读取多个字节。read()
方法在读取结束时返回-1
,可以作为循环结束的条件。 - 关闭流:使用完毕后,应调用
close()
方法关闭流,以释放相关资源。
import java.io.FileInputStream;
import java.io.IOException;
/**
* 示例:使用 FileInputStream 逐字节读取文件中的数据。
*/
public class FileInputStreamDemo {
public static void main(String[] args) {
FileInputStream fis = null;
try {
// 创建 FileInputStream 对象,指定要读取的文件路径
fis = new FileInputStream("E:/a.txt");
int byteData;
// 循环读取数据,每次读取一个字节,直到文件末尾
while ((byteData = fis.read()) != -1) {
// 将读取的字节转换为字符并输出
System.out.print((char) byteData);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭输入流,释放资源
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
# 3. 每次读取一个字节数组 (批量读取)
为了提高效率,特别是处理较大的文件时,可以使用字节数组一次读取多个字节的数据。这种方法通常用于需要高效读取大量数据的场景。
- **创建
FileInputStream
对象:**指定需要读取的文件路径,创建一个FileInputStream
实例。 - **读取数据:**使用
read(byte[] b)
方法将多个字节的数据读入到字节数组中。可以通过循环读取文件中的所有数据。 - **关闭流:**使用完毕后,应调用
close()
方法关闭流,以释放相关资源。
import java.io.FileInputStream;
import java.io.IOException;
/**
* 示例:使用 FileInputStream 读取字节数组的数据。
*/
public class FileInputStreamExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("E:/a.txt")) {
byte[] buffer = new byte[1024]; // 创建字节数组作为缓冲区
int len; // 每次读取的字节数
// 循环读取数据,每次读取一个字节数组的长度,直到文件末尾
while ((len = fis.read(buffer)) != -1) {
// 将读取的字节转换为字符串进行输出
System.out.print(new String(buffer, 0, len));
}
} 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
# 4. 异常的捕获处理
# 1. JDK7版本之前处理方式 : 手动释放资源
/*
需求 : 对上一个赋值图片的代码进行使用捕获方式处理
*/
public class FileInputStreamDemo4 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 创建字节输入流对象,用于读取原图片
fis = new FileInputStream("C:\\Users\\WuYimin\\Pictures\\图库\\123.png");
// 创建字节输出流对象,用于写入拷贝的图片
fos = new FileOutputStream("e:/picture/copy.jpg");
// 定义变量by,用于存放读取到的字节
int by;
// 循环读取原图片的字节,并写入到拷贝图片中
while ((by = fis.read()) != -1) {
fos.write(by); // 一次读写一个字节
}
} catch (IOException e) {
// 打印异常信息
e.printStackTrace();
} finally {
// 释放资源,首先判断fis是否为null,避免NullPointerException
if (fis != null) {
try {
fis.close(); // 尝试关闭fis流
} catch (IOException e) {
// 打印关闭fis流时的异常信息
e.printStackTrace();
}
}
// 同样的方式释放fos资源
if (fos != null) {
try {
fos.close(); // 尝试关闭fos流
} catch (IOException e) {
// 打印关闭fos流时的异常信息
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
# 2. JDK7版本优化处理方式 : 自动释放资源
在JDK7及以后的版本中,提供了一种新的异常处理机制——try-with-resources
语句,用以简化在处理资源时必须进行的关闭资源操作。这种机制特别适用于需要关闭的资源,比如各种类型的流、数据库连接等。使用try-with-resources
可以确保每个资源在语句结束时自动关闭,从而避免资源泄漏,并且使代码更加简洁易读。
格式:
try (资源初始化语句) {
// 使用资源的代码
} catch (异常类型 变量名) {
// 异常处理代码
}
2
3
4
5
- 其中,资源初始化语句通常是创建一个资源实例的语句。
- 资源必须实现
java.lang.AutoCloseable
或java.io.Closeable
接口,这两个接口都声明了void close()
方法,try-with-resources
语句会在代码块执行完毕后自动调用这个close()
方法来关闭资源。
示例代码:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileInputStreamDemo5 {
public static void main(String[] args) {
// 使用try-with-resources语句自动管理资源
try (
// 在try()中声明资源,这些资源会在try代码块执行完毕后自动关闭
FileInputStream fis = new FileInputStream("D:/scholar Gallery/scholarSave/wallhaven-wexe9r.jpg");
FileOutputStream fos = new FileOutputStream("D:/copy.jpg");
) {
// 读取源文件,并将内容写入目标文件
int by;
while ((by = fis.read()) != -1) {
fos.write(by);
}
// 注意:此处无需手动关闭流,try-with-resources语句已经自动处理
} 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
优势
- 自动管理资源,无需手动关闭,减少了代码量,提高了代码的可读性和可维护性。
- 提高资源管理的安全性,避免了忘记关闭资源导致的资源泄漏问题。
# 3. 图片的拷贝 (字节流应用场景)
使用字节输入流和字节输出流,可以有效地对二进制文件(如图片、音频、视频等)进行复制操作。
- 创建输入流对象:指定源文件路径来创建
FileInputStream
,用于读取源文件。 - 创建输出流对象:指定目标文件路径来创建
FileOutputStream
,用于写入数据到目标文件。 - 读取并写入数据:通过
read(byte[] b)
方法从源文件读取数据到字节数组,然后通过write(byte[] b, int off, int len)
方法将字节数组的数据写入目标文件。循环此过程直到文件末尾。 - 关闭流:操作完成后,关闭输入流和输出流以释放资源。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopy {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
// 创建FileInputStream对象,读取源图片
fis = new FileInputStream("C:\\Users\\WuYimin\\Pictures\\图库\\123.png");
// 创建FileOutputStream对象,指定拷贝图片的目标位置(目录不存在会报错)
fos = new FileOutputStream("E:/picture/fosCopy.jpg");
byte[] buffer = new byte[1024]; // 创建字节数组作为缓冲
int len; // 每次读取的字节数
// 边读边写,每次读取一个字节数组,直到文件末尾
while ((len = fis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
System.out.println("拷贝图片成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭输入流和输出流
try {
if (fis != null) {
fis.close();
}
if (fos != null) {
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
为什么需要创建字节数组作为缓冲?
通过使用字节数组作为缓冲,可以一次性读取或写入多个字节的数据。这样,每次磁盘I/O操作可以处理更多的数据,减少了磁盘访问次数,从而提高了数据处理的速度。例如,使用1024字节作为缓冲区大小,意味着每次可以读取或写入最多1024字节的数据,这比逐个字节处理要高效得多。