Использование inputstream для записи в другой поток с помощью Process()

#c# #process #inputstream #outputstream #memorystream

#c# #процесс #входной поток #outputstream #memorystream

Вопрос:

Я работаю над программой, которая должна принимать входной поток, а затем пропускать его через процесс, а затем выводить новый поток. Это для использования потока, состоящего из xml и xsl, и преобразования его в pdf с помощью wkhtmltopdf.exe и вывод PDF в виде потока. Любая помощь очень ценится.

Отредактируйте, чтобы добавить код и улучшить понимание:

В функцию я отправляю MemoryStream в качестве параметра и возвращаю байты[]. Текущий код, который у меня есть, выглядит следующим образом, но он не функционирует, поскольку я пытаюсь выяснить, как принять ввод потока, преобразовать его, а затем вернуть его снова как новый поток.

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;
    }
  

Комментарии:

1. Приветствуются любые детали, код и конкретные проблемы…

2. Конкретная проблема заключается в том, что я не знаю, как использовать поток в качестве входных данных.

3. Эти потоки ввода-вывода / E являются текстовыми потоками. Они не предназначены для двоичных данных. И даже если бы это было так, вы должны делать это с использованием многопоточности или асинхронного ввода-вывода — выходные данные должны постоянно считываться, иначе вы можете в конечном итоге заблокировать процесс. Например, вы не читаете StandardError , поэтому вы могли бы вызвать зависание процесса, если у него достаточно для записи в Error.

Ответ №1:

Ваш подход с использованием process частично неверен. Вы можете создать новый PDF-файл из существующего html-файла, но вам придется использовать два временных файла (один для html, второй для вывода в формате pdf). В этом сценарии рабочий процесс будет следующим: 1) Сохраните memoty stream как временный HTML-файл 2) запустите новый процесс (без перенаправления потока) — он создаст новый PDF-файл 3) Вернет новый PDF-файл как поток 4) очистите временные файлы, как только вы закончите

или

Вы можете использовать libwkhtmltox напрямую, используя PInvoke

или (лучший)

Вы можете использовать существующее решение, например, Pechkin, которое выполняет весь PInvoke и встроенное взаимодействие с библиотекой libwkhtmltox за вас: Использование Pechkin

Комментарии:

1. Мы хотим попытаться избежать сохранения файла на диск, поскольку это большой сервер, который будет обрабатывать много запросов, и один человек может получить доступ ко многим файлам.

2. чем использовать последнее предложение: использование Печкина

Ответ №2:

Нашел способ преодолеть проблему

 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 представляет собой memorystream, возвращаемый из функции XslCompiledTransform(). Затем это передается в GeneratePdf в StreamReader с encodingpage 850. Функция выглядит следующим образом:

 public MemoryStream GeneratePdf(StreamReader html)
    {
        html.BaseStream.Position = 0;
        var pdf = new MemoryStream();
        using (html)
        {
            Process p;
            var psi = new ProcessStartInfo
            {
                FileName = @"C:wkhtmltopdfwkhtmltopdf.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();
            }
        }
    }