0

我在我们的一个系统中遇到了一个奇怪的错误,我无法解释。在我们的系统中,后端正在生成一个大型 TSV 输出文件,然后我们使用以下代码通过 HTTP 提供该文件:

    BufferedInputStream input = new BufferedInputStream(p.getInputStream(), (int)FileUtils.BYTES_PER_MEGABYTE * 16);
    OutputStream output = resp.getOutputStream();
    byte[] buffer = new byte[(int) (FileUtils.BYTES_PER_KILOBYTE * 8)];
    do
    {
        int read = input.read(buffer);
        if (read <= 0) break;
        output.write(buffer);           
    } while (true);
    input.close();
    output.close();

然后在客户端有一个 TSV 解析器消耗 HTTP 响应,但是在非常大的输入上,我们开始看到奇怪的工件,其中解析器将报告一行具有错误的项目数,并且错误消息打印它将解析的行和该行将是随机数据块,即不是整行数据

我的第一个想法是生成的 TSV 格式不正确,但我通过直接从后端系统复制文件,然后通过三个独立编写的开源 TSV 解析器(包括客户端代码使用的那个)运行它,几乎排除了这种情况) 并且在本地文件上运行时,它们都能够很好地解析文件。

作为参考,我们使用的 TSV 解析器的代码在这里

这使我有两种可能性:

  1. 我展示的用于通过 HTTP 复制文件的代码在某些方面存在缺陷 - 在这种情况下,我希望有人指出我犯了哪些愚蠢但不明显的错误!
  2. BufferedReader.readLine()消费解析器正在使用哪个不能保证读取整行?如果是这种情况,我不会完全感到惊讶,因为我被 .Net 中慢速网络流上的奇怪读取行为所困扰,所以想知道类似的问题是否适用于 Java?

还是我忽略了其他一些解释?

4

1 回答 1

1

在发布这个问题时,我突然发现错误是什么(通常!)

我发布的用于复制文件的代码的以下部分不正确:

int read = input.read(buffer);
if (read <= 0) break;
output.write(buffer);

它应该如下所示:

int read = input.read(buffer);
if (read <= 0) break;
output.write(buffer, 0, read);

问题是我总是将整个缓冲区写入输出流,即使我们从输入中读取的内容少于缓冲区的大小。这意味着在文件的末尾,我们将打印最后一块数据以及缓冲区中剩余的任何内容,因此剩下的随机数据块!

于 2012-07-03T20:56:36.540 回答