.Net執行cmd命令


using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Diagnostics;

namespace WebForm
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Response.Write(ExeCommand("ping www.126.com"));
        }

        public string ExeCommand(string commandText)
        {
            Process p = new Process();
            p.StartInfo.FileName = "cmd.exe";
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardInput = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.CreateNoWindow = true;
            string strOutput = null;
            try
            {
                p.Start();
                p.StandardInput.WriteLine(commandText);
                p.StandardInput.WriteLine("exit");
                strOutput = p.StandardOutput.ReadToEnd();
                p.WaitForExit();
                p.Close();
            }
            catch (Exception e)
            {
                strOutput = e.Message;
            }
            return strOutput;
        }
    }
}

 

 

 

WaitForExit

程序里我使用Process類啟動命令行,執行批處理文件 'Create.cmd'(當我手工將此文件拖入命令行執行時,一切正常)。C#程序代碼類似如下,其中batchFilePath變量為批處理文件全路徑:

 

C小Tip:Process.WaitForExit()與死鎖  - fengqiaa - 風之築的博客C小Tip:Process.WaitForExit()與死鎖  - fengqiaa - 風之築的博客Code

m_BasicDataProc = new Process();

m_BasicDataProc.StartInfo.FileName = "cmd.exe";

m_BasicDataProc.StartInfo.CreateNoWindow = false;

m_BasicDataProc.StartInfo.UseShellExecute = false;

m_BasicDataProc.StartInfo.RedirectStandardOutput = true;

m_BasicDataProc.StartInfo.RedirectStandardInput = true;

m_BasicDataProc.StartInfo.WorkingDirectory = Path.GetDirectoryName(batchFilePath);

m_BasicDataProc.Start();

string batchFileName = Path.GetFileName(batchFilePath);

StreamWriter inputStream = m_BasicDataProc.StandardInput;

inputStream.WriteLine(batchFileName);

inputStream.Close();

m_BasicDataProc.WaitForExit();

m_BasicDataProc.EnableRaisingEvents = true;

 

批處理文件'Create.cmd'調用'sqlplus'來執行若干個sql文件:

//===================================================

echo Tables on level 0:

if exist InstallScripts\Create01.sql (

echo bas

sqlplus %1/%2@%3 @InstallScripts\Create01.sql | %HideSQLPlusRows%

REM > Logs\Create_%1.txt

)

if exist InstallScripts\Create02.sql (

......

//===================================================

出現的問題是程序運行到'm_BasicDataProc.WaitForExit();'這一行時就陰塞不動.

搞 了兩天,最后發現原因是出現了死鎖。由於標准輸出流被重定向,而Process.StandardOutput的緩沖大小是有限制的(據說是4k),所以 當緩沖滿了的時候(執行上面的批處理文件有很多的輸出),子進程(cmd.exe)會等待主進程(C# App)讀取並釋放此緩沖,而主進程由於調用了WaitForExit()方法,則會一進等待子進程退出,最后形成死鎖。

了解了原因后,有3種方法可以解決問題:

1)修改批處理文件,在調用sqlplus時將輸出指定到一個log文件,這樣被生定向到StandardOutput中的內容相對就少,不容易造成問題:

//===================================================

echo Tables on level 0:

if exist InstallScripts\Create01.sql (

echo bas

sqlplus %1/%2@%3 @InstallScripts\Create01.sql | %HideSQLPlusRows% > Logs\Create_%1.txt

)

......

//===================================================

2)修改C#代碼,將'm_BasicDataProc.StartInfo.RedirectStandardOutput = false;',這樣所有的輸出會在命令行屏幕上直接輸出,不會重定向到標准輸出流中。

3) 修改C#代碼,在'm_BasicDataProc.WaitForExit();'前添加 'm_BasicDataProc.BeginOutputReadLine();' 或 'm_BasicDataProc.StandardOutput.ReadToEnd();',通過讀取輸出流,以便釋放相應的緩沖。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM