使用Java通过Windows上的外部应用程序管理数据

时间:2011-01-20 18:52:37

标签: java named-pipes inputstream command-line-interface outputstream

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

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

你怎么建议我这样做?有没有办法在Java中访问Windows命名管道,还是可以通过套接字来实现?别的什么?这将以1 /秒的速度完成,因此开销不能太高。

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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;

答案 2 :(得分:0)

我建议使用ZIP压缩,它是J2SE库的一部分(参见java.util.zip docs),除非使用FreeArc有很大的性能优势(比如说1秒对10秒),或者ZIP没有提供足够好的压缩。如果您热衷于使用FreeArc,有几种不同的复杂选项:

  1. 将输入转储到文件,使用ProcessBuilder对其运行实用程序,然后将压缩文件传输到输出。您应该使用NIO通道而不是流 - 这可能会减少IO开销(特别是发送出去)。对于纯Java而言,这是唯一可以做的事情,显然不是最佳的性能。
  2. 使用JNI +本机FreeArc API(如果有的话,它允许在流/字节缓冲区上运行)。
  3. 使用JNI +本机Windows API创建一个连接您的应用程序和FreeArc的命名管道,然后您可以使用它与常规文件非常相似。
  4. 最后,如果输入或输出是文件,则可以减少文件IO。例如。如果从文件中读取 - 只需直接对其运行FreeArc,然后将压缩文件发送到输出。 如果a)数据大小相对较小,也可能不值得这么麻烦 - 可能高达几兆;或b)压缩不会显着降低