从InputStream读取并写入OutputStream

3

这应该非常简单,我已经在谷歌上搜索了,但没有看到任何人提到我注意到的问题。我看到的所有内容都做了同样基本的事情。就像这样:

byte [] buffer = new byte[256];
int bytesRead = 0;
while((bytesRead = input.read(buffer)) != -1)
{
    output.write(buffer, 0, bytesRead);
}

我知道当读到EOF时,read()函数会返回-1,但是如果文件比缓冲区甚至同样大小还要小呢?例如,正在读取一个200字节的文件。我假设它已经读取了这200个字节,但是返回-1。这符合Java文档的描述,但也意味着write()从未被调用。我本来期望它告诉我它已经读取了这200个字节,并在下一次迭代中返回-1。
如何解决这个“问题”?

展示在调用 read() 函数之前,input 是如何创建并被处理的。 - erickson
目前而言,这个问题是“不完整的”。 - erickson
5个回答

12

Guava,我之前没听说过。我发现很多谷歌Java库非常有用。我看了一下copy()的代码,它基本上做的就是我要做的事情,但在我的情况下write()从未被调用。我会再次检查我的代码。这就是我期望的工作方式。就像所有评论中所说的那样。 - Amac

7

您的代码

byte [] buffer = new byte[256];
int bytesRead = 0;
while((bytesRead = input.read(buffer)) != -1) {
    output.write(buffer, 0, bytesRead);
}

正常工作。

例如,想象一下,您有一个包含300个字符(600个字节)的文件:

步骤1. 缓冲区将读取256个字节并将其重写到输出中;还剩344个字节到EOF

步骤2. 缓冲区将读取256个字节并将其重写到输出中;还剩88个字节到EOF

步骤3. 缓冲区将读取88个字节(byteRead == 88)并将其重写到输出中;EOF剩余

步骤4. EOF (input.read(buffer) 返回 -1)

...编辑

以上步骤不是理论。我通过使用此代码重写实际文件内容来获得这些步骤:

static void rewrite() throws IOException {
    InputStream input = new FileInputStream("file1.txt");
    OutputStream output = new FileOutputStream("file2.txt");
    byte[] buffer = new byte[256];
    int bytesRead = 0;
    while ((bytesRead = input.read(buffer)) != -1) {
        System.out.println(bytesRead);
        output.write(buffer, 0, bytesRead);
    }
}

也许你的配置出了其他问题。

这是我期望的结果,但在第三步它返回了-1。我会再次逐步检查我的代码,但我已经做了几次并得到了相同的结果。 - Amac

1

至少需要两次调用read()才能检测到非空流的结束。一次读取内容,另一次返回EOF。

例如,如果缓冲区为256字节,文件只有200字节,则调用read(byte[])将返回200(或一系列调用结果将总和为200),然后随后的调用将返回-1以表示EOF。

并不完全清楚您如何解释InputStream的Javadoc,但它明确表示它返回读取的字节数,并且仅在没有更多数据可读时返回-1。

如果b的长度为零,则不会读取任何字节,并返回0;否则,将尝试读取至少一个字节。如果没有字节可用,因为流已到达文件末尾,则返回值为-1;否则,将读取至少一个字节并存储到b中。

进一步:

返回:已读入缓冲区的总字节数,或-1 [如果]没有更多数据,因为已到达流的末尾。


2次读取?这正是我所期望的,但事实并非如此。如果我的文件比我使用的缓冲区小,则在第一次调用raad()时返回-1。它技术上已经到达了EOF,因此它正在执行javadoc所说的操作。然而,它没有提到它已经读取的200个字节。使用像我发布的while循环那样,write()永远不会被调用。 - Amac
@user1209868 那么你的代码其他地方存在 Bug。(你的帖子未显示从打开文件到此时读取返回 -1 的完整流历史记录。)如上所述,文档清楚地指定如果可以读取任何字节,则返回非负计数;Javadoc 说如果读取了一些字节将返回 -1。要么你的流本来就是空的,要么某些前置操作已经消耗了它所持有的数据。 - erickson

0

read()函数返回读取的字节数,直到完整文件被读取。当无法再读取更多字节时,它只会返回-1。

来自Java文档(1.4)

如果没有字节可用,因为流已经到达文件末尾,则返回值为-1;否则,至少读取并存储一个字节到b中。

它实际上可以做你想要的事情。它读取200个字节(或者文件中剩余的比你提供的缓冲区小的字节数),并在下一次迭代中返回-1。


我理解 javadoc 中所说的内容。当我调用 read() 时,它会填充缓冲区直到达到 EOF (我的缓冲区比文件大)。就像文档中所述,它会返回 -1。它确实这样做了,但是它不应该先告诉我已经读取了200个字节,然后在后续的 read() 调用中返回 -1 吗? - Amac
@user1209868 当它读取到 EOF 时,它会返回 -1,而不是在此之前。如果它读取到了内容,它会返回已读取的字节数。 - user207421

0
我认为它读取了200个字节,但返回-1。
不,它读取了200个字节并返回200。这在Javadoc中非常清楚,并且您也可以轻松地尝试一下。

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