【第七章】I/O输入输出:文件字节流

1.字节流的概念

在程序的开发中,我们经常会需要处理设备之间的数据传输,而计算机中,无论是文本、图片、音频还是视频,所有文件都是以二进制(字节)形式存在的。

而对于字节的输入输出IO流提供了一系列的流,统称为字节流,字节流是程序中最常用的流,根据数据的传输方向可将其分为字节输入流和字节输出流。

JDK中,提供了两个抽象类InputStreamOutputStream,它们是字节流的顶级父类,所有的字节输入流都继承自InputStream,所有的字节输出流都继承自OutputStream。为了方便理解,可以把InputStreamOutputStream比作两根“水管”

在上图中,InputStream被看成一个输入管道,OutputStream被看成一个输出管道,数据通过InputStream从源设备输入到程序,通过OutputStream从程序输出到目标设备,从而实现数据的传输。由此可见,IO流中的输入输出都是相对于程序而言的。

JDK中,InputStream OutputStream提供了一系列与读写数据相关的方法

方法声明

功能描述

int read()

从输入流读取一个8位的字节,把它转换为0~255之间的整数,并返回这一整数

int read(byte[] b)

从输入流读取若干字节,把它们保存到参数b指定的字节数组中,返回的整数表示读取字节的数目

int read(byte[] b,int offint len)

从输入流读取若干字节,把它们保存到参数b指定的字节数组中,off指定字节数组开始保存数据的起始下标,len表示读取的字节数目

void close()

关闭此输入流并释放与该流关联的所有系统资源

在上面表格中,第一个read()方法是从输入流中逐个读入字节,而第二个和第三个read()方法则将若干字节以字节数组的形式一次性读入,从而提高读数据的效率。

在进行IO流操作时,当前IO流会占用一定的内存,由于系统资源宝贵,因此,在IO操作结束后,应该调用close()方法关闭流,从而释放当前IO流所占的系统资源。

InputStream对应的是OutputStreamOutputStream是用于写数据的,因此OutputStream提供了一些与写数据有关的方法,OutputStream的常用方法如

方法名称

方法描述

void write(int b)

向输出流写入一个字节

void write(byte[] b)

把参数b指定的字节数组的所有字节写到输出流

void write(byte[] b,int off,int len)

将指定byte数组中从偏移量off开始的len个字节写入输出流

void flush()

刷新此输出流并强制写出所有缓冲的输出字节

void close()

关闭此输出流并释放与此流相关的所有系统资源

上述表格列举了OutputStream类的五个常用方法。

前三个是重载的write()方法,都是用于向输出流写入字节,其中,第一个方法逐个写入字节,后两个方法是将若干个字节以字节数组的形式一次性写入,从而提高写数据的效率。

flush()方法用来将当前输出流缓冲区(通常是字节数组)中的数据强制写入目标设备,此过程称为刷新。

close()方法是用来关闭流并释放与当前IO流相关的系统资源。

InputStreamOutputStream这两个类虽然提供了一系列和读写数据有关的方法,但是这两个类是抽象类,不能被实例化,因此,针对不同的功能,InputStreamOutputStream提供了不同的子类,这些子类形成了一个体系结构

InputStream的子类如下图。

OnputStream的子类如下图。

InputStream就是JDk提供的基本输入流。但InputStream并不是一个接口,而是一个抽象类,它是所有输入流的父类,而FileInputStreamInputStream的子类,它是操作文件的字节输入流,专门用于读取文件中的数据。由于从文件读取数据是重复的操作,因此需要通过循环语句来实现数据的持续读取。

2. InputStream读文件

接下来通过一个案例来实现字节流对文件数据的读取。在实现案例之前,首先在Java项目的根目录下创建一个文本文件test.txt,在文件中输入内容“itcast”并保存;然后使用字节输入流对象来读取test.txt文本文件

import java.io.*;
public class Example08 {
	public static void main(String[] args) throws Exception {
		// 创建一个文件字节输入流
		FileInputStream in = new FileInputStream("test.txt");
		int b = 0;           // 定义一个int类型的变量b,记住每次读取的一个字节
		while (true) {
			b = in.read(); // 变量b记住读取的一个字节
			if (b == -1) { // 如果读取的字节为-1,跳出while循环
				break;
			}
			System.out.println(b); // 否则将b写出
		}
		in.close();
	}
}

上述代码中,5行代码创建的字节流FileInputStream,第7~13行代码通过read()方法将当前项目中的文件“test.txt”中的数据读取并打印。

从运行结果可以看出,控制台打印的结果分别为1051169997115116由于计算机中的数据都是以字节的形式存在的。在“test.txt”文件中,字符‘i’、‘t’、‘c’、‘a’、‘s’、‘t’各占一个字节,因此,最终结果显示的就是文件“test.txt”中的六个字节所对应的十进制数。

3 OnputStream文件

OutputStreamJDK提供的最基本的输出流,与InputStream类似的是OutputStream也是抽象类,它是所有输出流的父类。OutputStream是一个抽象类,如果使用此类,则首先必须通过子类实例化对象。FileOutputStreamOutputStream的子类,它是操作文件的字节输出流,专门用于把数据写入文件。

接下来通过一个案例来演示如何使用FileOutputStream将数据写入文件

import java.io.*;
public class Example10
	public static void main(String[] args) throws Exception {
		// 创建一个文件字节输出流
		OutputStream out = new FileOutputStream("example.txt");//绝对路径
		String str = "你的名字+学号";
		byte[] b = str.getBytes();
		for (int i = 0; i < b.length; i++) {
			out.write(b[i]);
		}
		out.close();
	}
}

4.代码提升

题目描述:编写一个Java程序,实现将一个文本文件a.txt中的内容逐行读取,并将每行内容逆序写入到另一个文件b.txt中。
要求使用FileInputStream读取源文件内容,
使用FileOutputStream将逆序后的内容写入到目标文件。
a.txt文件内容:我是一个测试内容
1.a.txt在D盘手动创建,包括内容
2.b.txt用代码创建
3.实现逆序内容的保存

import java.io.*;

public class ReverseFileContent {
    public static void main(String[] args) {
        File sourceFile = new File("D:/a.txt");
        File targetFile = new File("b.txt");

        try (BufferedReader reader = new BufferedReader(new FileReader(sourceFile));
             BufferedWriter writer = new BufferedWriter(new FileWriter(targetFile))) {

            String line;
            while ((line = reader.readLine()) != null) {
                StringBuilder reversedLine = new StringBuilder(line).reverse();
                writer.write(reversedLine.toString());
                writer.newLine();
            }

            System.out.println("文件内容逆序写入成功!");

        } catch (IOException e) {
            System.out.println("文件操作失败:" + e.getMessage());
        }
    }
}

5.字节缓冲流

IO提供两个带缓冲的字节流,分别是BufferedInputStreamBufferedOutputStream,它们的构造方法中分别接收InputStreamOutputStream类型的参数作为对象,在读写数据时提供缓冲功能。应用程序、缓冲流和底层字节流之间的关系如下图。

接下来通过一个案例学习BufferedInputStreamBufferedOutputStream 这两个流的用法。首先在Java项目的根目录下创建一个名称为src.txt的文件,并在该文件中随意写入一些内容;然后创建一个类,在类中使用FileOutputStream创建文件des.txt,并使用字节缓冲流对象将文件src.txt中的内容拷贝到文件des.txt

import java.io.*;
public class Example14 {
	public static void main(String[] args) throws Exception {
		// 创建一个带缓冲区的输入流
		BufferedInputStream bis = new BufferedInputStream(new 
					FileInputStream("src.txt"));
		// 创建一个带缓冲区的输出流
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream("des.txt"));
		int len;
		while ((len = bis.read()) != -1) {
			bos.write(len);
		}
		bis.close();
		bos.close();
	}
}

上述代码中,5~6行代码分别创建了BufferedInputStreamBufferedOutputStream两个缓冲流对象,这两个流内部都定义了一个大小为8192的字节数组,第11~12行代码中调用read()或者write()方法读写数据时,首先将读写的数据存入定义好的字节数组,然后将字节数组的数据一次性读写到文件中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值