将大文件作为流发送到process.getOutputStream

时间:2010-11-13 05:59:25

标签: java runtime io stream outputstream

我在windows机器中使用gzip实用程序。我压缩了一个文件并作为blob存储在DB中。当我想使用gzip实用程序解压缩此文件时,我将此字节流写入process.getOutputStream。但是在30KB之后,它无法读取文件。它挂在那里。

尝试使用内存参数,读取和刷新逻辑。但是,如果我尝试写入文件,那么相同的数据非常快。

 OutputStream stdin = proc.getOutputStream();
 Blob blob = Hibernate.createBlob(inputFileReader);
 InputStream source = blob.getBinaryStream();
 byte[] buffer = new byte[256];
 long readBufferCount = 0;
 while (source.read(buffer) > 0)
 {
  stdin.write(buffer);
  stdin.flush();
  log.info("Reading the file - Read bytes: " + readBufferCount);
  readBufferCount = readBufferCount + 256;
 }
 stdin.flush();

此致 Mani Kumar Adari。

1 个答案:

答案 0 :(得分:1)

我怀疑问题是外部进程(连接到proc)是

  • 没有阅读其标准输入,或
  • 它正在向Java应用程序不读取的标准输出中写入内容。

请记住,Java使用一对“管道”与外部进程通信,并且这些缓冲区的数量有限。如果超过管道的缓冲容量,则写入进程将被阻止写入管道,直到读取器进程从管道读取足够的数据以腾出空间。如果读者没有读取,那么管道就会锁定。

如果您提供了更多上下文(例如,启动gzip进程的应用程序部分),我将能够更加明确。

<强>后续

  

gzip.exe是我们正在使用的Windows中的unix实用程序。 gzip.exe在命令提示符下工作正常。但不是与java程序。有没有什么办法可以增加java写入管道的缓冲区大小。我担心目前的输入部分。

在UNIX上,gzip实用程序通常使用以下两种方法之一:

  • gzip file压缩file将其转换为file.gz
  • ... | gzip | ...(或类似的东西)将其标准输入的压缩版本写入其标准输出。

我怀疑你做的是后者,java应用程序既是gzip命令输入的源,又是输出的目的地。这正是可以锁定的场景......如果java应用程序没有正确实现。例如:

    Process proc = Runtime.exec(...);  // gzip.exe pathname.
    OutputStream out = proc.getOutputStream();
    while (...) {
        out.write(...);
    }
    out.flush();
    InputStream in = proc.getInputStream();
    while (...) {
        in.read(...);
    }

如果上面的应用程序的写入阶段写入太多数据,则可以保证锁定。

java应用程序和gzip之间的通信是通过两个管道进行的。正如我上面所说,管道将缓冲一定数量的数据,但这个数量相对较小,并且肯定是有限的。这是锁定的原因。以下是发生的事情:

  1. 创建gzip进程时使用一对管道将其连接到Java应用程序进程。
  2. Java应用程序将数据写入其out
  3. gzip进程从其标准输入读取数据,压缩并写入其标准输出。
  4. 步骤2.和3.重复几次,直到最后gzip进程尝试写入其标准输出块。
  5. 正在发生的事情是gzip已经写入其输出管道,但没有任何内容正在从中读取。最终,我们达到了我们已经耗尽输出管道的缓冲容量以及写入管道块的程度。

    与此同时,Java应用程序仍在写入out Stream,经过几轮之后,这也会因为我们填充了另一个管道而阻塞。

    唯一的解决方案是Java应用程序同时读取和写入 。执行此操作的简单方法是创建第二个线程,并从一个线程写入外部进程,并从另一个线程读取进程。

    (更改Java缓冲或Java读/写大小无济于事。重要的缓冲是在管道的OS实现中,如果有的话,没有办法从纯Java改变它。)< / p>