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

标签 java runtime io stream outputstream

我在 Windows 机器上使用 gzip 实用程序。我压缩了一个文件并作为 blob 存储在数据库中。当我想使用 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。

最佳答案

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

  • 不读取它的标准输入,或者
  • 它正在将您的 Java 应用程序未读取的内容写入其标准输出。

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

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

跟进

gzip.exe is a unix utility in windows we are using. gzip.exe in command prompt working fine. But Not with the java program. Is there any way we can increase the buffering size which java writes to a pipe. I am concerned about the input part at present.

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

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

我怀疑您正在执行与后者相同的操作,将 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 进程尝试写入其标准输出 block 。

发生的事情是 gzip 一直在写入其输出管道,但没有从中读取任何内容。最终,我们到达了耗尽输出管道缓冲容量的地步,并且写入管道阻塞。

与此同时,Java 应用程序仍在向 out 流写入数据,再经过几轮之后,这也会阻塞,因为我们已经填满了另一个管道。

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

(更改 Java 缓冲或 Java 读/写大小无济于事。重要的缓冲存在于管道的操作系统实现中,并且无法从纯 Java 中更改它,如果有的话。)

关于java - 将大文件作为流发送到 process.getOutputStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4171213/

相关文章:

java - 在结束后不关闭 InputStream 有什么意义?

java - Selenium webdriver Java如何等待链接出现

iOS类方法

algorithm - 经典 Cracking the Coding 面试题的运行时间 a^3 + b^3 = c^3 + d^3?

c++ - 在运行时删除/修改静态 Qt 资源

c# - 如何检查用户输入是来自条码扫描器还是键盘?

android - phonegap html5 android 同步文件系统 IO

java - 从 RSA 编码的 AES key 生成 AES key

java - 在 Android 应用程序中使用 facebook 登录

java - 检查三个 boolean 值中的至少两个是否为真