3

我有一个带有 InputStream 的 Java 应用程序,它将数据复制到 OutputStream。我想使用 FreeArc 压缩来自 InputStream 的数据,然后再将其写入 OutputStream。

问题是没有针对 FreeArc 的 Java-API。因此,我需要以某种方式通过命令行 exe 对其进行管道传输。即,当它实际上是从我的 InputStream 读取并写入我的 OutputStream 时,我必须欺骗 FreeArc 它正在读取和写入两个文件。在 Unix 上这很简单,但我必须在 Windows 上完成这项工作。

你建议我怎么做?有没有办法在 Java 中访问 Windows 的命名管道,或者我可以通过套接字进行访问?还有什么?这将完成 ~1/sec,因此开销不能太高。

4

3 回答 3

2

如果 freearc 可以从标准输入获取输入并将输出发送到标准输出,则ProcessBuilder可以用于调用命令,Process返回的实例将暴露外部进程的标准输入和输出。

于 2011-01-20T19:16:27.163 回答
1

下面是一个示例,取自旨在通过 GhostScript 将 EPS 转换为 PDF 的代码:

  // Start the script as OS process.
  ProcessBuilder pb = new ProcessBuilder(gsExecutable, pdfFileName, epsFile.getName());
  pb.directory(gsDir);
  pb.redirectErrorStream(true);
  Process proc = pb.start();
  final InputStream stdErrInStream = proc.getErrorStream();
  final InputStream stdOutInStream = proc.getInputStream();

  // Read the STDERR-Stream.
  String className = EpsToJpegConverter.class.getName();
  final ByteArrayOutputStream stdErrOutStream = new ByteArrayOutputStream();
  new Thread(new Runnable() {
    @Override
    public void run() {
      try {
        byte[] buf = new byte[16];
        int len = -1;
        while ((len = stdErrInStream.read(buf)) != -1) {
          stdErrOutStream.write(buf, 0, len);
        }
        stdErrFertig = true;
      } catch (IOException e) {
        log.error(e.getLocalizedMessage(), e);
      }
    }
  }, className + " Script STDERR Reader").start();

  // Read the STDOUT-Stream.
  final ByteArrayOutputStream stdOutOutStream = new ByteArrayOutputStream();
  new Thread(new Runnable() {
    @Override
    public void run() {
      try {
        byte[] buf = new byte[4096];
        int len = -1;
        while ((len = stdOutInStream.read(buf)) != -1) {
          stdOutOutStream.write(buf, 0, len);
        }
        stdOutFertig = true;
      } catch (IOException e) {
        log.error(e.getLocalizedMessage(), e);
      }
    }
  }, className + " Script STDOUT Reader").start();

  // Wait for the process to finish.
  int waitFor = proc.waitFor();
  if (waitFor != 0) {
    // If an error occured, the return code is != 0.
    // In this case wait for the reading threads to finish.
    while (!stdOutFertig || !stdErrFertig) {
      Thread.sleep(100);
    }
    throw new EpsConverterException("Das Konvertierungsscript " + gsExecutable
        + " wurde nicht erfolgreich ausgeführt.\nStandardausgabe:\n" + new String(stdOutOutStream.toByteArray())
        + "\nFehlerausgabe:\n" + new String(stdErrOutStream.toByteArray()));
  }

HTH。

编辑:也许读取转换后的图像字节的代码也很有趣:

  // If everything worked out ok, read the PDF.
  pdfFile = new File(gsDir, pdfFileName);
  FileInputStream pdfInStream = new FileInputStream(pdfFile);
  int len = -1;
  byte[] buf = new byte[4096];
  ByteArrayOutputStream pdfBAOS = new ByteArrayOutputStream(65535);
  while ((len = pdfInStream.read(buf)) != -1) {
    pdfBAOS.write(buf, 0, len);
  }
  pdfInStream.close();

  byte[] res = pdfBAOS.toByteArray();
  return res;
于 2011-10-27T13:06:45.340 回答
0

我建议使用作为 J2SE 库一部分的 ZIP 压缩(请参阅java.util.zip文档),除非使用 FreeArc 有巨大的性能优势(比如 1 秒与 10 秒),或者 ZIP 不能提供足够好的压缩。如果你热衷于使用 FreeArc,有几个不同复杂度的选项:

  1. 将您的输入转储到文件,使用 对它运行实用程序ProcessBuilder,然后将压缩文件传输到输出。您应该使用 NIO 通道而不是流 - 这可能会稍微减少 IO 开销(尤其是发送出去)。这是纯 Java 唯一可以做的事情,而且在性能方面显然不是最好的。
  2. 使用 JNI + 原生 FreeArc API(如果有的话,它允许对流/字节缓冲区进行操作)。
  3. 使用 JNI + 本机 Windows API 创建一个命名管道,将您的应用程序和 FreeArc 连接起来,然后您可以像使用常规文件一样使用它。

最后,如果输入或输出都是文件,则可以减少文件 IO。例如,如果您从文件中读取 - 只需直接对其运行 FreeArc,然后将压缩文件发送到输出。此外,如果 a) 数据大小相对较小 - 可能高达几兆,则可能不值得这么麻烦;或 b) 压缩不会显着减少它

于 2011-11-02T18:04:36.063 回答