首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用RedirectStandardInput和RedirectStandardOutput调用jpegOptim

使用RedirectStandardInput和RedirectStandardOutput调用jpegOptim
EN

Stack Overflow用户
提问于 2015-11-05 11:00:34
回答 1查看 228关注 0票数 1

我正在尝试做一些看起来相对简单的事情:从C#调用jpegoptim。

我可以让它很好地写入磁盘,但是到目前为止,让它接受一个流并发出一个流是我所不能理解的--我总是以0长度的输出结束,或者是不祥的“管道已经结束”。

我尝试过一种方法:

代码语言:javascript
复制
var processInfo = new ProcessInfo(
    jpegOptimPath,
    "-m" + quality + " -T1 -o -p --strip-all --all-normal"
);
processInfo.CreateNoWindow = true;
processInfo.WindowStyle = ProcessWindowStyle.Hidden;
processInfo.UseShellExecute = false;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;

using(var process = Process.Start(processInfo))
{
    await Task.WhenAll(
        inputStream.CopyToAsync(process.StandardInput.BaseStream),
        process.StandardOutput.BaseStream.CopyToAsync(outputStream)
    );

    while (!process.HasExited)
    {
        await Task.Delay(100);
    }

    // Do stuff with outputStream here - always length 0 or exception
}

我也尝试过这个解决方案:

http://alabaxblog.info/2013/06/redirectstandardoutput-beginoutputreadline-pattern-broken/

代码语言:javascript
复制
using (var process = new Process())
{
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.RedirectStandardError = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.FileName = fileName;
    process.StartInfo.Arguments = arguments;

    process.Start();

    //Thread.Sleep(100);

    using (Task processWaiter = Task.Factory.StartNew(() => process.WaitForExit()))
    using (Task<string> outputReader = Task.Factory.StartNew(() => process.StandardOutput.ReadToEnd()))
    using (Task<string> errorReader = Task.Factory.StartNew(() => process.StandardError.ReadToEnd()))
    {
        Task.WaitAll(processWaiter, outputReader, errorReader);

        standardOutput = outputReader.Result;
        standardError = errorReader.Result;
    }
}

同样的问题。输出长度为0。如果我让jpegoptim在没有输出重定向的情况下运行,我会得到我所期望的-一个优化的文件-但当我以这种方式运行它时就不是这样了。

一定要有正确的方法才能做到这一点?

更新:发现了一个线索-我不觉得害羞吗- jpegoptim从来没有支持管道到stdin,直到2014年的一个实验性构建,今年修复。我的版本来自一个更老的库,日期是2013年。https://github.com/tjko/jpegoptim/issues/6

EN

回答 1

Stack Overflow用户

发布于 2015-11-06 00:39:34

部分解决方案-参见下面的死锁问题。我在最初的尝试中遇到了多个问题:

jpegoptim你需要一个构建的来读写管道,而不是只读写文件。正如前面提到的builds prior to mid-2014 can't do it。jpegoptim github "releases“是无用的源代码压缩,而不是构建的发行版,所以您需要在其他地方寻找实际的built releases.

  1. You需要正确地调用它,传递--stdin--stdout,并根据您将如何响应它,避免可能导致它什么都不写的参数,比如-T1 (当优化只有1%或更少时,
  2. 您需要执行以下重要任务:在Process类
  3. 上重定向输入和输出,并避免输入端的缓冲区溢出,这将使您再次获得0输出-明显的stream.CopyToAsync()溢出进程的非常有限的4096字节(4K)缓冲区,但什么也得不到。

太多的路都没有了。没有任何迹象表明原因。

代码语言:javascript
复制
var processInfo = new ProcessInfo(
    jpegOptimPath,
    "-m" + quality + " --strip-all --all-normal --stdin --stdout",
);

processInfo.CreateNoWindow = true;
processInfo.WindowStyle = ProcessWindowStyle.Hidden;

processInfo.UseShellExecute = false;
processInfo.RedirectStandardInput = true;
processInfo.RedirectStandardOutput = true;
processInfo.RedirectStandardError = true;

using(var process = new Process())
{
    process.StartInfo = processInfo;

    process.Start();

    int chunkSize = 4096;   // Process has a limited 4096 byte buffer
    var buffer = new byte[chunkSize];
    int bufferLen = 0;
    var inputStream = process.StandardInput.BaseStream;
    var outputStream = process.StandardOutput.BaseStream;

    do
    {
        bufferLen = await input.ReadAsync(buffer, 0, chunkSize);
        await inputStream.WriteAsync(buffer, 0, bufferLen);
        inputStream.Flush();
    }
    while (bufferLen == chunkSize);

    do
    {
        bufferLen = await outputStream.ReadAsync(buffer, 0, chunkSize);
        if (bufferLen > 0)
            await output.WriteAsync(buffer, 0, bufferLen);
    }
    while (bufferLen > 0);

    while(!process.HasExited)
    {
        await Task.Delay(100);
    }

    output.Flush();

这里有一些需要改进的地方。欢迎改进。

最大的问题是:在一些图片中,这个死锁发生在

  • outputStream.ReadAsync行上。
  • 它属于单独的方法来分解它-我展开了一堆方法来保持这个例子,它是一堆刷新,可能不是necessary.
  • The代码,这里的代码是用来处理任何流入和流出的东西的。4096是任何进程都会处理的硬限制,但假设所有输入都进入,然后所有输出都出来,这可能是一个糟糕的假设,根据我的研究,可能会导致其他类型的进程死锁。看起来jpegoptim的行为是这样的(非常缓冲,非常不像管道……)方法--stdin --stdout但是,这段代码很好地处理了这个特定的任务。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33535933

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档