<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>StandardOutput 彙整 - 泰克哪裡去</title>
	<atom:link href="https://tech.uccu.website/tag/standardoutput/feed" rel="self" type="application/rss+xml" />
	<link>https://tech.uccu.website/tag/standardoutput</link>
	<description>一個科技相關的隨手記錄網站</description>
	<lastBuildDate>Thu, 10 Mar 2022 04:27:06 +0000</lastBuildDate>
	<language>zh-TW</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.1</generator>
<site xmlns="com-wordpress:feed-additions:1">119574712</site>	<item>
		<title>C#透過Process的StandardInput輸入Stream時卡住的可能問題</title>
		<link>https://tech.uccu.website/process-standard-input-output-deadlock.html?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=process-standard-input-output-deadlock</link>
					<comments>https://tech.uccu.website/process-standard-input-output-deadlock.html#respond</comments>
		
		<dc:creator><![CDATA[鳴人]]></dc:creator>
		<pubDate>Thu, 10 Mar 2022 04:26:59 +0000</pubDate>
				<category><![CDATA[.Net]]></category>
		<category><![CDATA[程式設計]]></category>
		<category><![CDATA[Process]]></category>
		<category><![CDATA[StandardInput]]></category>
		<category><![CDATA[StandardOutput]]></category>
		<category><![CDATA[Tika]]></category>
		<guid isPermaLink="false">https://tech.uccu.website/?p=1712</guid>

					<description><![CDATA[<p>事情是這樣子的…前兩天同事跟我說有一個使用了Tika的程式在處理txt文字檔有時候不知道什麼原因會卡住死掉，問 ... <a title="C#透過Process的StandardInput輸入Stream時卡住的可能問題" class="read-more" href="https://tech.uccu.website/process-standard-input-output-deadlock.html" aria-label="Read more about C#透過Process的StandardInput輸入Stream時卡住的可能問題">閱讀全文</a></p>
<p>這篇文章 <a href="https://tech.uccu.website/process-standard-input-output-deadlock.html">C#透過Process的StandardInput輸入Stream時卡住的可能問題</a> 最早出現於 <a href="https://tech.uccu.website">泰克哪裡去</a>。</p>
]]></description>
										<content:encoded><![CDATA[
<p>事情是這樣子的…<br>前兩天同事跟我說有一個使用了<a href="https://tika.apache.org/" target="_blank" rel="noreferrer noopener">Tika</a>的程式在處理txt文字檔有時候不知道什麼原因會卡住死掉，問我可不可以改用CancellationToken的方式讓它超過時間就取消處理？</p>



<p>程式碼大概是這樣的…</p>



<span id="more-1712"></span>



<pre class="wp-block-prismatic-blocks"><code class="language-csharp">public string Extract(Stream stream)
{
    var Arg = $&quot;-jar {TikaPath} -t --encoding=UTF-16 -&quot;;

    //run Tika

    var p = new Process();
    p.StartInfo.FileName = JavaPath;
    p.StartInfo.Arguments = Arg;
    p.StartInfo.CreateNoWindow = true;
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardInput = true;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();

    var stdin = p.StandardInput.BaseStream;
    stream.CopyTo(stdin);
    stdin.Close();

    var output = p.StandardOutput.ReadToEnd();
    p.WaitForExit();

    return output;
}</code></pre>



<p>從別的地方讀取了檔案之後呼叫了這個方法，傳入了一個Stream，透過Stream.CopyTo的方式將傳入的內容複製到Tika的StandardInput，用ConsoleApp很簡單的弄了一個測試，逐步執行的時候會發現就卡在Stream.CopyTo這個地方，但是如果是pdf檔案就可以順利執行。</p>



<p>Stream.CopyTo有一個非同步的方法是CopyToAsync，稍微試了一下就算用了CancellationToken嘗試在超過時間要取消操作，實際上仍然是沒辦法中止卡在這個地方的情況。而且這樣根本也不知其所以然，到底為什麼卡住還是不知道原因。</p>



<p>OK，既然是卡在這個Stream複製的地方，而且不同的檔案(txt vs pdf)在相同的程式碼是不同的結果，pdf可以正常執行，txt卻不行，那就是txt檔案的內容在輸入StandardInput的時候發生了問題。</p>



<p>想要知道發生什麼問題，過程中還試了StandardError，要看看是不是發生什麼錯誤輸出了錯誤訊息到這裡面，不過從內容中去找尋線索未果，不過在<a href="https://docs.microsoft.com/zh-tw/dotnet/api/system.diagnostics.process.standarderror?view=net-6.0" target="_blank" rel="noreferrer noopener">官方文件上</a>看到有可能發生死結的情況，不知道為何卻想到試著改用內容較少的txt檔案，在同樣的程式碼運行卻可以正常。</p>



<p>最終在多個不同的假設測試下，發現會卡住的原因是txt檔案太大，內容過多的情況下會卡在Stream.CopyTo這個環節，所以判斷可能是在複製到StandardInput的過程中也會將處理的結果輸出到StandardOutput，但是StandardOutput一直收收收，收到緩衝區滿了沒處理，CopyTo這裡傳給Tika，Tika說「你等等，我在等Output處理」，我們的程式是在後面才呼叫StandardOutput.ReadToEnd，所以在Stream.CopyTo的這裡一直等Tika接收完內容，最終形成了死結…</p>



<p>處理這個問題不困難，除了StandardOutput.ReadToEnd這個方式處理內容之外，它還有個非同步的處理方式，在前面先建立一個StringBuilder來接收內容，最後再改成從StringBuilder取得所有內容，結果就是相同的。最後修改後的程式碼如下：</p>



<pre class="wp-block-prismatic-blocks"><code class="language-csharp">public string Extract(Stream stream) 
{
    var Arg = $&quot;-jar {TikaPath} -t --encoding=UTF-16 -&quot;;

    //run Tika

    StringBuilder output = new StringBuilder();

    var p = new Process();
    p.StartInfo.FileName = JavaPath;
    p.StartInfo.Arguments = Arg;
    p.StartInfo.CreateNoWindow = true;
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardInput = true;
    p.StartInfo.RedirectStandardOutput = true;

    p.StartInfo.StandardOutputEncoding = Encoding.BigEndianUnicode;
    p.OutputDataReceived += new DataReceivedEventHandler((s, e) =&gt; output.AppendLine(e.Data));

    p.Start();
    p.BeginOutputReadLine();

    var stdin = p.StandardInput.BaseStream;
    stream.CopyTo(stdin);
    stdin.Close();

    p.WaitForExit();

    return output.ToString();
}</code></pre>



<p>修改後的內容改用OutputDataReceived事件處理每次收到的Output內容放入StringBuilder，只是這邊有個地方要特別注意，那就是StandardOutput的Encoding要特別設定，不然結果會和使用StandardOutput.ReadToEnd的內容不同(編碼不同)。</p>



<p>參考資訊：</p>



<ul class="wp-block-list"><li><a href="https://docs.microsoft.com/zh-tw/dotnet/api/system.diagnostics.process.standarderror" target="_blank" rel="noreferrer noopener">https://docs.microsoft.com/zh-tw/dotnet/api/system.diagnostics.process.standarderror</a></li><li><a href="https://docs.microsoft.com/zh-tw/dotnet/api/system.diagnostics.process.standardinput" target="_blank" rel="noreferrer noopener">https://docs.microsoft.com/zh-tw/dotnet/api/system.diagnostics.process.standardinput</a></li><li><a href="https://stackoverflow.com/questions/26384772/deadlock-while-writing-to-process-standardinput" target="_blank" rel="noreferrer noopener">https://stackoverflow.com/questions/26384772/deadlock-while-writing-to-process-standardinput</a></li><li><a href="https://stackoverflow.com/questions/36918007/beginoutputreadline-and-encoding" target="_blank" rel="noreferrer noopener">https://stackoverflow.com/questions/36918007/beginoutputreadline-and-encoding</a></li><li><a href="https://docs.microsoft.com/en-us/sysinternals/downloads/procmon" target="_blank" rel="noreferrer noopener">https://docs.microsoft.com/en-us/sysinternals/downloads/procmon</a></li><li><a href="https://blog.darkthread.net/blog/977/" target="_blank" rel="noreferrer noopener">https://blog.darkthread.net/blog/977/</a></li></ul>
<p>這篇文章 <a href="https://tech.uccu.website/process-standard-input-output-deadlock.html">C#透過Process的StandardInput輸入Stream時卡住的可能問題</a> 最早出現於 <a href="https://tech.uccu.website">泰克哪裡去</a>。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://tech.uccu.website/process-standard-input-output-deadlock.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1712</post-id>	</item>
	</channel>
</rss>
