使用Process()使用输入流写入另一个流

时间:2014-07-03 08:36:17

标签: c# process inputstream outputstream memorystream

我正在开发一个需要获取输入流然后将其推送到进程然后输出新流的程序。这是为了使用由xml和xsl组成的流,并通过wkhtmltopdf.exe将其转换为pdf,并将pdf作为流输出。非常感谢任何帮助。

编辑以添加代码和更好的理解:

进入函数我发送一个MemoryStream作为参数,我正在返回bytes []。我当前的代码看起来像这样,但它没有运行,因为我正在试图弄清楚如何获取流输入,转换它然后再将其作为新流返回。

code

public byte[] WKHtmlToPdf(MemoryStream inputStream)
{
        var fileName = " - ";
        _workingDirectory = ""; \\there is a directory here but contains company name
                                \\so I removed it
        _wkhtmlexe = wkhtmltopdf.exe";
        var p = new Process();

        p.StartInfo.CreateNoWindow = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.RedirectStandardInput = true;
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.FileName = _wkhtmlexe;
        p.StartInfo.WorkingDirectory = _workingDirectory;

        StreamWriter inpuStreamWriter = new StreamWriter(inputStream);
        inpuStreamWriter = p.StandardInput;
        StreamReader outpStreamReader = p.StandardOutput;

        string switches = "";
        switches += "--print-media-type ";
        switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm ";
        switches += "--page-size Letter ";
        p.StartInfo.Arguments = switches + " " + inputStream + " " + fileName;
        p.Start();





        inpuStreamWriter.Write();

        //read output
        byte[] buffer = new byte[32768];
        byte[] file;
        using (var ms = inputStream)
        {
            while (true)
            {
                int read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);

                if (read <= 0)
                {
                    break;
                }
                ms.Write(buffer, 0, read);
            }
            file = ms.ToArray();
        }

        // wait or exit
        p.WaitForExit(60000);

        // read the exit code, close process
        int returnCode = p.ExitCode;
        p.Close();
        return returnCode == 0 ? file : null;
    }

2 个答案:

答案 0 :(得分:0)

您使用流程的方法部分错误。您可以从现有的html文件创建新的pdf文件,但必须使用两个临时文件(一个用于html,第二个用于pdf输出)。在这种情况下,工作流程将是: 1)将memoty流保存为临时html文件 2)运行新进程(没有流重定向) - 它生成新的pdf文件 3)将新的pdf文件作为流返回 4)完成后清理临时文件

您可以直接使用PInvoke

使用libwkhtmltox

或(最佳)

您可以使用现有的解决方案,例如Pechkin为您执行所有PInvoke以及与 libwkhtmltox 库的本机合作:Pechkin usage

答案 1 :(得分:0)

找出克服问题的方法

private static void GeneratePdfFromStream()
    {
        var ms = xml_and_xsl_to_html();
        File.WriteAllBytes(Constants.FilesResultHtml, ms.ToArray());

        var printer = new Printer();
        var pdfStream = printer.GeneratePdf(new StreamReader(ms, Encoding.GetEncoding(850), false));
        File.WriteAllBytes(Constants.FilesResultPdf, pdfStream.ToArray());
    }

变量ms是从XslCompiledTransform()函数返回的内存流。然后将其传递给streamReader中的GeneratePdf,其编码页面为850.该函数如下所示:

public MemoryStream GeneratePdf(StreamReader html)
    {
        html.BaseStream.Position = 0;
        var pdf = new MemoryStream();
        using (html)
        {
            Process p;
            var psi = new ProcessStartInfo
            {
                FileName = @"C:\wkhtmltopdf\wkhtmltopdf.exe",
                UseShellExecute = false,
                CreateNoWindow = true,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                Arguments = Switches() + "-q -n --enable-smart-shrinking " + " - -"
            };
            p = Process.Start(psi);
            try
            {
                if (p != null)
                {
                    var stdin = p.StandardInput;
                    stdin.AutoFlush = true;
                    stdin.Write(html.ReadToEnd());

                    stdin.Dispose();
                }
                CopyStream(p.StandardOutput.BaseStream, pdf);
                Console.WriteLine(  p.StandardOutput.CurrentEncoding.CodePage);
                p.StandardOutput.Close();
                pdf.Position = 0;
                p.WaitForExit(10000);
                return pdf;
            }
            catch
            {
                return null;
            }
            finally
            {
                if (p != null) p.Dispose();
            }
        }
    }