IO流及网络编程中的思考与疑问
在io流的复习过程中,产生了挺多的疑问,在与ai的对话过程中得到了详细的解释,学习效率提高,真思考,真实践。共勉!
public void readFile01() {
String filePath = "e:\\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);//转成 char 显示
}
疑问1:
这里的readData不是指读取的大小吗,为什么可以显示读取的内容呢?
答:
在 Java 的 FileInputStream
类中,read()
方法有几种重载形式,但在这个上下文中,使用的是无参数的 read()
方法。这个方法从输入流中读取数据的下一个字节。返回的是读取的字节作为 int
类型的值,范围从 0 到 255。如果到达文件末尾,则返回 -1
。
当你将 read()
方法的返回值(即 readData
)转换为 char
类型并打印时,你实际上是在将字节值解释为字符并打印出来。在 ASCII 字符集中,每个字符都有一个对应的字节值(对于扩展 ASCII 和 Unicode 字符,情况更为复杂,但这里我们主要讨论 ASCII)。因此,通过将字节值强制转换为 char
,你可以将文件的字节内容作为字符打印到控制台。
这里的关键是理解 read()
方法返回的是字节值,而不是读取的字节数。尽管在某些上下文中,“读取的数据”可能被误解为读取的字节数,但在这个例子中,它指的是从文件中读取的单个字节的值。
如果你想要读取一定数量的字节到一个数组中,你应该使用 read(byte[] b, int off, int len)
方法,它尝试读取最多 len
个字节到字节数组 b
中,从偏移量 off
开始。这个方法返回的是实际读取的字节数,这可能小于请求的字节数(如果到达文件末尾)。
疑问2:
那无参数的 read() 方法为啥要返回int而不是char?
答:
无参数的 read()
方法在 FileInputStream
(以及许多其他输入流类)中返回 int
而不是 char
的原因主要是出于灵活性和兼容性的考虑。
- 负值表示文件结束:使用
int
类型允许方法返回一个特殊的值-1
来表示文件末尾(EOF)。如果方法返回char
类型,则无法有效地表示 EOF,因为char
类型无法存储-1
(在 Java 中,char
是一个无符号的 16 位数据类型,其值范围是从 0 到 65535)。 - 字节扩展:虽然 ASCII 字符集可以用一个字节(即 0 到 255 的范围)来表示,但 Java 中的
char
类型实际上是基于 Unicode 的,它使用两个字节(即 16 位)来表示一个字符。这意味着即使你只关心 ASCII 字符,使用char
类型也会浪费空间。更重要的是,对于非 ASCII 字符(如中文、日文、阿拉伯文等),单个char
可能不足以表示一个完整的字符(尽管在 Java 中,这些字符通常使用char
数组或String
来表示,其中每个char
实际上是 UTF-16 编码的一部分)。然而,对于文件读取操作来说,我们通常更关心的是字节级别的数据,而不是字符级别的数据。 - 向后兼容和灵活性:选择
int
而不是char
也可能是为了保持与早期 Java 版本或其他编程语言中类似 API 的向后兼容性。此外,int
类型提供了比char
类型更多的灵活性,因为它可以表示更大的数值范围,这在处理字节数据时可能很有用(尽管在这个特定的read()
方法中,只有 0 到 255 的值和 -1 是有意义的)。 - 性能考虑:虽然这不是主要原因,但使用
int
而不是char
可能对性能有轻微影响。然而,在现代 Java 虚拟机(JVM)上,这种差异通常是可以忽略不计的。
综上所述,无参数的 read()
方法返回 int
而不是 char
主要是出于表示文件末尾、字节扩展、向后兼容性和灵活性的考虑。在处理字节数据时,使用 int
类型可以更方便地表示所有可能的字节值和文件末尾的情况。