一尘不染

从Process.StandardOutput捕获二进制输出

c#

在C#(在SuSE的Mono 2.8下运行的.NET 4.0)中,我想运行外部批处理命令并以二进制形式捕获其输出。我使用的外部工具称为“
samtools”(samtools.sourceforge.net),除其他外,它还可以从称为BAM的索引二进制文件格式返回记录。

我使用Process.Start运行外部命令,并且我知道可以通过重定向Process.StandardOutput捕获其输出。问题是,这是带有编码的文本流,因此它无法让我访问输出的原始字节。我发现几乎可行的解决方案是访问基础流。

这是我的代码:

        Process cmdProcess = new Process();
        ProcessStartInfo cmdStartInfo = new ProcessStartInfo();
        cmdStartInfo.FileName = "samtools";

        cmdStartInfo.RedirectStandardError = true;
        cmdStartInfo.RedirectStandardOutput = true;
        cmdStartInfo.RedirectStandardInput = false;
        cmdStartInfo.UseShellExecute = false;
        cmdStartInfo.CreateNoWindow = true;

        cmdStartInfo.Arguments = "view -u " + BamFileName + " " + chromosome + ":" + start + "-" + end;

        cmdProcess.EnableRaisingEvents = true;
        cmdProcess.StartInfo = cmdStartInfo;
        cmdProcess.Start();

        // Prepare to read each alignment (binary)
        var br = new BinaryReader(cmdProcess.StandardOutput.BaseStream);

        while (!cmdProcess.StandardOutput.EndOfStream)
        {
            // Consume the initial, undocumented BAM data 
            br.ReadBytes(23);

// …随后进行更多解析

但是,当我运行此命令时,我读取的前23个字节不是输出中的前23个字节,而是下游的数百或数千个字节。我假设StreamReader进行了一些缓冲,因此基础流已经提前输出了4K。基础流不支持从头开始搜索。

我被困在这里。有没有人有运行外部命令并以二进制形式捕获其标准输出的有效解决方案?输出可能很大,因此我想对其进行流式处理。

任何帮助表示赞赏。

顺便说一句,我当前的解决方法是让samtools以文本格式返回记录,然后解析它们,但这非常慢,我希望直接使用二进制格式来加快处理速度。


阅读 623

收藏
2020-05-19

共1个答案

一尘不染

使用StandardOutput.BaseStream是正确的方法,但是您不能使用的任何其他属性或方法cmdProcess.StandardOutput。例如,访问cmdProcess.StandardOutput.EndOfStream将使StreamReaderfor
StandardOutput读取流的一部分,从而删除要访问的数据。

相反,只需读取并解析其中的数据br(假设您知道如何解析数据,并且不会读取流的末尾或愿意捕获EndOfStreamException)。另外,如果您不知道数据有多大,请使用Stream.CopyTo将整个标准输出流复制到新文件或内存流中。

2020-05-19