将 ByteArrayOutputStream 发送到 Perl 脚本,然后读取响应

Send ByteArrayOutputStream to Perl script, then read response

我有一个 ByteArrayOuputStream,我通过执行 diff 收到了它。 Java 对此的解析太慢了,所以我决定尝试将解析传递给 Perl 脚本。我在让脚本从这个输出流接收数据时遇到了一些麻烦。当我 运行 我的代码时,应用程序无限期挂起。这是我目前所拥有的:

public static Diff analyzeDiff(ByteArrayOutputStream baos) throws IOException {

    ProcessBuilder pb = new ProcessBuilder();
    pb.command("perl/path/perl", TEMP.getAbsolutePath());
    Process process = pb.start();
    OutputStream str = process.getOutputStream();
    baos.writeTo(str);
    str.flush();
    try {
        process.waitFor();
    } catch (InterruptedException e) {
        BufferedReader bf = new BufferedReader(new InputStreamReader(process.getInputStream()));
        String line;
        while ((line = bf.readLine()) != null) {
            System.out.println(line);
        }
    }

    return null;
}

@Test
public void testDiffParser() throws IOException {
    DiffParser.init();

    File test = new File("path/to/file/test.diff");

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    baos.write(FileUtils.readFileToByteArray(test));
    //String output = baos.toString();
    //System.out.println(output);

    DiffParser.analyzeDiff(baos);
    //DiffParser.analyzeDiff(output);
}

这是我的 Perl 脚本:

#!/usr/bin/perl
use strict;
use warnings;

my $additions = 0;
my $deletions = 0;
my $filesChanged = 0;

my $fileAdded = 0;
my $line;

foreach $line ( <> ) {
    $_ = $line;
    chomp( $_ );
    print( $_ );
    if ( /^\-\-\-/m ) {
        $fileAdded = 1;
    } elsif ( /^\+\+\+/m && $fileAdded ) {
        $filesChanged++;
        $fileAdded = 0;
    } elsif ( /^\+/ ) {
        $additions++;
        $fileAdded = 0;
    } elsif ( /^\-/ ) {
        $deletions++;
        $fileAdded = 0;
    } else {
        $fileAdded = 0;
    }
}

print("$additions $deletions $filesChanged\n")

有没有办法真正做到我想做的事情?

编辑: 这就是我在 Java 中的做法:

private Diff parseDiff(final ByteArrayOutputStream baos) {

    final Diff diff = new Diff();

    int filesChanged = 0;
    int additions = 0;
    int deletions = 0;

    boolean fileAdded = false;

    final String[] lines = baos.toString().split("\n");

    for (final String line : lines) {

        if (line.startsWith("---")) {
            fileAdded = true;
        } else if (line.startsWith("+++") && fileAdded) {
            filesChanged++;
            fileAdded = false;
        } else if (line.startsWith("+")) {
            additions++;
            fileAdded = false;
        } else if (line.startsWith("-")) {
            deletions++;
            fileAdded = false;
        } else {
            fileAdded = false;
        }

    }

    diff.additions = additions;
    diff.deletions = deletions;
    diff.changedFiles = filesChanged;

    return diff;
}

编辑 2 如果你想要一些上下文,你可以参考这个 Related question

我目前正在使用平板电脑,所以帮不上什么忙,但是您的 Perl 需要一些改进。

您不应使用 for $line ( <> ),因为它会在开始迭代之前尝试将输入的 所有 读取到列表中。你也不使用 $line 所以你应该直接读入 $_

while ( <> ) { ... }

也没有必要每行chomp,我不明白为什么每条记录都调用print?它在 chomp 之后,因此输出将是输入的副本,所有内容都在一行很长的行中,最后是聚合值。

我怀疑 Perl 脚本可以很好地接收数据,但无法同时将所有输入与所有内容的第二个副本一起放入内存作为输出!

使用ByteArrayOutputStream意味着diff的整个结果需要一次全部存储在内存中,而不是分块进行处理和垃圾收集。由于 运行 内存不足并一直执行垃圾回收,您的 Java 程序可能运行缓慢。

与 Perl 相比,

Java 无论你交给它什么任务,它都会快得多。它是一种即时编译语言,与 Perl 中的解释语言相反。参见例如http://blog.carlesmateo.com/2014/10/13/performance-of-several-languages/, https://attractivechaos.github.io/plb/ or https://en.wikipedia.org/wiki/Java_performance(与其他语言的比较)。

如果您需要性能,您应该优化您的 Java 代码,而不是创建对 Perl 的依赖。