3

我在 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();

问候,玛尼·库马尔·阿达里。

4

1 回答 1

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进程尝试写入其标准输出块。

发生的事情是它gzip一直在写入它的输出管道,但没有从它读取。最终,我们已经耗尽了输出管道的缓冲区容量,并且写入管道阻塞。

同时,Java 应用程序仍在写入outStream 写入数据,经过几轮之后,这也被阻塞了,因为我们已经填充了另一个管道。

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

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

于 2010-11-13T06:39:14.317 回答