Java中FileInputStream和FileOutputStream是如何工作的?

4
我正在阅读关于Java中所有输入/输出流的内容,参考Java Tutorials Docs。教程作者使用了以下示例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyBytes {
    public static void main(String[] args) throws IOException {

        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            in = new FileInputStream("xanadu.txt");
            out = new FileOutputStream("outagain.txt");
            int c;

            while ((c = in.read()) != -1) {
                out.write(c);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}

xanadu.txt文件数据:

In Xanadu did Kubla Khan
A stately pleasure-dome decree:
Where Alph, the sacred river, ran
Through caverns measureless to man
Down to a sunless sea.

将输出写入outagain.txt文件:

In Xanadu did Kubla Khan
A stately pleasure-dome decree:
Where Alph, the sacred river, ran
Through caverns measureless to man
Down to a sunless sea.
  1. 为什么作者即使我们读取字符,也要使用int c

  2. 为什么在while条件中使用-1

  3. out.write(c);方法如何将int再次转换为字符?


它们不是字符,它们是字节。你熟悉Java API文档吗?标准Java库中的每个类和方法都有解释,包括FileInputStreamFileOutputStream。当你不确定为什么会调用某个方法时,从中学习很重要。 - RealSkeptic
@RealSkeptic Java教程文档看起来简单易懂,用户友好,但Java API文档看起来一团糟。这就是为什么我正在阅读教程文档的原因。无论如何,我会尝试从那里阅读。 - user5028722
它们不是学习编程的来源。它们是每个类的详细解释。因此,每当您在教程中看到使用一个类时,应该在API文档中查找它。那里才是重要信息所在。 - RealSkeptic
@RealSkeptic 好的,谢谢。 - user5028722
一个“我不想读JavaDoc,请帮我做研究”的问题能得到5个赞吗? - Tom
2个回答

6
1: 我们读取字符,为什么作者使用了 int c?
FileInputStream.read() 返回一个数据字节作为 int。这是可行的,因为字节可以在不失精度的情况下表示为 int。查看此答案以了解为什么返回 int 而不是 byte。
2: 第二个问题是,为什么在 while 条件中使用 -1?
当到达文件结尾时,会返回 -1。
3: out.write(c) 方法如何将 int 再次转换为字符,并提供与 outagain.txt 文件相同的输出?
FileOutputStream.write() 接受一个字节参数作为 int。由于 int 涵盖的值比 byte 更多,因此给定 int 的 24 高阶位被忽略,使其成为兼容字节的值:在 Java 中,int 始终为32位。通过删除24个高阶位,你将得到一个8位值,即一个字节。
我建议您仔细阅读每个方法的Javadoc。作为参考,它们可以回答你所有的问题: read:
从输入流中读取下一个数据字节。返回值字节作为范围在 0 到 255 的 int。如果没有可用字节,因为已经到达了流的末尾,则返回值 -1。此方法阻塞直到有输入数据可用,已检测到流的结尾或引发异常。 write:
将指定的字节写入此输出流。write 的一般契约是写入一个字节到输出流中。要写入的字节是参数 b 的八个低位。b 的24高阶位被忽略。

出色的..一切都清除了..!! - user5028722
抱歉,您所说的“b的24个高位被忽略”是什么意思?有示例吗? - user5028722
2
在Java中,int类型始终为32位。通过移除高24位,您将得到一个8位值,即一个字节。 - Tunaki
快速问题:从文件中读取字节后,这些字节存储在哪里:在RAM、缓冲区中。我的意思是,字节是如何从输入流传递到输出流的? - CKM

1

请阅读文档。

这里是read方法的文档http://docs.oracle.com/javase/7/docs/api/java/io/FileInputStream.html#read()

public int read() throws IOException 从此输入流中读取一个字节的数据。如果尚无输入,则此方法将阻塞。

指定者: InputStream 类中的 read

返回: 下一个数据字节;如果已到达文件末尾,则返回 -1。

那个int是你下一组字节数据。现在,以下是答案。

1)当你将char赋值给int时,它将其ascii码转换为int。

如果您感兴趣,这里是字符及其ascii代码的列表https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html

2)-1表示已到达文件末尾。因此,这是检查数据是否存在的方法。

当您向打印机发送ASCII代码时,它会将相应的字符打印到文件中。

@SURESH 解释得很清楚。只有一个问题,如何将字节转换为整数?隐式地? - user5028722
1
你为什么谈论字符和PrintWriters,而我们在这里处理的是字节流?这里没有char,如果文件不是ASCII / UTF-8等格式,而是UTF-16,那么读取的内容将不一定是一个字符,而是一个单独的字节。 - RealSkeptic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接