使用 Java 通过 Windows 上的外部应用程序传输数据

发布于 2024-10-13 01:57:57 字数 355 浏览 5 评论 0原文

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

问题是没有针对 FreeArc 的 Java-API。因此,我需要以某种方式通过命令行 exe 通过管道传输它。也就是说,我必须愚弄 FreeArc,它正在读取和写入两个文件,而实际上它是从我的 InputStream 读取并写入我的 OutputStream。在 Unix 上这非常简单,但我必须使其在 Windows 上工作。

你建议我怎样做?有没有办法在 Java 中访问 Windows 的命名管道,或者我可以通过套接字进行访问吗?还有别的事吗?这将大约1/秒完成,因此开销不会太高。

I have a Java-app with an InputStream, which is copying data to an OutputStream. I want to compress the data from the InputStream using FreeArc, before writing it to the OutputStream.

The problem is that there's no Java-API against FreeArc. I therefore need to pipe it through the command-line exe somehow. I.e. I have to fool FreeArc that it's reading and writing two files when it's in fact reading from my InputStream and writing to my OutputStream. On Unix this is quite straightforward but I have to make this work on Windows.

How do you suggest I do that? Is there a way to access Windows' Named Pipes in Java or can I do it over sockets? Something else? This will be done ~1/sec so the overhead can't be too high.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

为你拒绝所有暧昧 2024-10-20 01:57:57

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

If freearc can take input from standard in and send output to standard out, then ProcessBuilder can be used to invoke the command and the Process instance returned will expose the external process' standard input and output.

清秋悲枫 2024-10-20 01:57:57

以下是取自通过 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;

Here is an example taken from code meant to convert EPS to PDF via GhostScript:

  // 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.

Edit:
Maybe the code that reads the converted image bytes back is also of interest:

  // 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;
缪败 2024-10-20 01:57:57

我建议使用 ZIP 压缩,它是 J2SE 库的一部分(请参阅 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) 压缩不会显着减少

I would suggest to use ZIP compression which is part of J2SE library (see java.util.zip docs), unless there are huge performance benefits in using FreeArc (say 1 sec vs. 10 sec), or ZIP doesn't provide good enough compression. If you're keen to use FreeArc,there are several options of different complexity:

  1. Dump your input to file, run utility against it using ProcessBuilder, then transfer compressed file to output. You should use NIO channels instead of streams - that might reduce IO overhead a bit (especially for sending out). That's the only thing you can do with pure Java, and clearly not the best in terms of performance.
  2. Use JNI + native FreeArc API (if there is any, and it allows to operate on streams / byte buffers).
  3. Use JNI + native Windows API to create a named pipe that will connect your app and FreeArc, then you can work with that pretty much like with regular file.

Finally, you can reduce file IO if either input or output is a file. E.g. if you read from a file - just run FreeArc against it directly, and then send compressed file to output.
Also it may not worth all that trouble if a) data size is relatively small - up to several megs maybe; or b) compression doesn't reduce it dramatically

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文