异步获取进程输出信息,控制其他线程的操作
问题描述:
我的项目需要将3个文件压缩成rar文件,其中包括动态生成的1.swf、1.mp3文件还有另一个较大的2.mp3文件。
已确定的两个基本步骤是
1.进程对象1调用rar.exe压缩生成自动运行1.swf的自解压文件1.exe。
2. 进程对象2再次调用rar.exe将1.exe文件压缩成1.rar文件。(主要为了能够作为安全附件发送)
现在有这样一个问题,如果2.mp3文件过大,会造成用于生成的1.exe的Process实例p1还没有运行完毕,第二个Process实例p2就开始了,致使1.rar无法生成或生成失败。
开始我试了根据mp3的体积来动态加入线程延迟Thread.Sleep(n)来延迟p2的Start()调用,可是并不很理想,这样毕竟不是很准确。
那么有没有好的办法,可以得到P1运行完毕的状态,再开始运行P2呢?
答案是肯定的,我们可以获取进程输出信息流,然后根据它的信息来进一步控制处理其他线程的操作。
根据msdnhttp://msdn.microsoft.com/zh-cn/vstudio/system.diagnostics.process.beginoutputreadline.aspx
我们知道调用外部程序的进程输出信息有异步和同步两种方式。
同步和异步两种方式都做了测试都可以实现我的需求,同步方式的代码已作注释
下例中代码分别为进程_ExeProcess和_RarProcess注册委托方法ExeOutputHandler和RarOutputHandler。分别负责获取进程OutputDataReceived时的输出信息,在调用BuileExe()的委托线程执行后才执行调用BuildRar()的委托线程。其中RarOutputHandler中还负责控制_isDone的全局状态。这样客户端就可以根据IsDone属性来已经启动压缩程序的控制应用程序何时可以退出。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using DBCoreEngine;
namespace ClientCoreEngine
{
public class RarShell : IDisposable
{
private MediaManager m = new MediaManager();
private Process _ExeProcess = new Process();
private Process _RarProcess = new Process();
private Thread _ExeThread;
private Thread _RarThread;
private ProcessStartInfo _startInfo = new ProcessStartInfo();
private int _inOriginalMp3Size;
private bool _isRunning = false;
private bool _isDone = false;
private string _inswfFile;
private string _inOriginalmp3File;
private string _inUsermp3File;
private string _outFile;
private string startupfile;
private static readonly string dataDir = "myData";
private string workpath = Path.Combine(Application.StartupPath, dataDir);
private readonly string _optionsExe = " a -zinfo.txt -sfx";
private readonly string _optionsRar = " a ";
private int _ExeOKLines = 0;
private int _RarOKLines = 0;
public bool IsDone
{
get { return _isDone; }
set { _isDone = value; }
}
public string OptionsRar
{
get { return _optionsRar; }
}
private string _infofile = "info.txt";
public string InSwfFile
{
get { return _inswfFile; }
set { _inswfFile = value; }
}
public string InOriginalMp3File
{
get { return _inOriginalmp3File; }
set { _inOriginalmp3File = value; }
}
public string InUserMp3File
{
get { return _inUsermp3File; }
set { _inUsermp3File = value; }
}
public string OutFile
{
get { return _outFile; }
set { _outFile = value; }
}
public string Options
{
get { return _optionsExe; }
}
public string RarPath
{
get { return _startInfo.WorkingDirectory; }
set { _startInfo.WorkingDirectory = value; }
}
public string Startupfile
{
get { return startupfile; }
set { startupfile = value; }
}
public string Infofile
{
get { return _infofile; }
set { _infofile = value; }
}
public RarShell()
{
if (_inswfFile != null)
{
InitialRarConfig();
}
DefStartInfo();
_startInfo.WorkingDirectory = workpath;
}
public RarShell(string InSwfFile, string InMp3File, string OutFile, string RarPath, string Options)
{
if (InSwfFile != string.Empty)
{
InitialRarConfig(InSwfFile);
}
DefStartInfo();
if (string.IsNullOrEmpty(RarPath))
_startInfo.WorkingDirectory = workpath;
_inswfFile = InSwfFile;
_inUsermp3File = InMp3File;
_outFile = OutFile;
_optionsExe = Options;
}
private void DefStartInfo()
{
_startInfo.FileName = "myData\\rar.exe";
_startInfo.UseShellExecute = false;
_startInfo.RedirectStandardOutput = true;
_startInfo.RedirectStandardError = true;
_startInfo.CreateNoWindow = true;
}
private void InitProcessStartInfo()
{
string arguments = "";
_ExeProcess = new Process();
if (_optionsExe != "")
arguments = _optionsExe + " ";
if (OutFile != "") arguments += OutFile + " ";
if (InSwfFile != "")
arguments += InSwfFile + " ";
if (InOriginalMp3File != "")
{
arguments += " " + InOriginalMp3File + " ";
//得到待加入原始mp3文件的大小KB
_inOriginalMp3Size = Convert.ToInt32(new FileInfo(Path.Combine(workpath, InOriginalMp3File)).Length / 1024);
}
if (InUserMp3File != "")
arguments += " " + InUserMp3File + " ";
_startInfo.Arguments = arguments;
_ExeProcess.StartInfo = _startInfo;
_ExeProcess.OutputDataReceived += new DataReceivedEventHandler(ExeOutputHandler);
}
public bool Start()
{
if (_isRunning || _inUsermp3File == string.Empty || _inswfFile == string.Empty || _outFile == string.Empty)
return false;
_isRunning = true;
InitProcessStartInfo();
try
{
InitialRarConfig();
_ExeThread = new Thread(new ThreadStart(BuildExe));
_ExeThread.IsBackground = true;
_ExeThread.Priority = ThreadPriority.Highest;
_ExeThread.Name = "BuildExe";
//生成exe
_ExeThread.Start();
_RarThread = new Thread(new ThreadStart(BuildRar));
_RarThread.IsBackground = true;
_RarThread.Priority = ThreadPriority.Highest;
_RarThread.Name = "BuildRar";
return true;
}
catch
{
return false;
}
}
private void ExeOutputHandler(object sendingProcess,DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{
if (outLine.Data.ToUpper().Contains("OK"))
{
_ExeOKLines++;
}
if (outLine.Data.Contains("完成") && _ExeOKLines >= 2)
{
_RarThread.Start();
}
}
}
private void RarOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
{
if (outLine.Data.ToUpper().Contains("OK"))
{
_RarOKLines++;
}
if (outLine.Data.Contains("完成") && _RarOKLines >= 1)
{
_isDone = true;
_RarProcess.WaitForExit();
_RarProcess.Close();
}
}
}
private void BuildRar()
{
//while (!File.Exists(Path.Combine(workpath, OutFile + ".exe")))
//{ Thread.Sleep(1000); }
//Thread.Sleep(_inOriginalMp3Size);
_RarProcess = new Process();
_startInfo.Arguments = string.Format(" {0} \"{1}\" \"{1}.exe\"", OptionsRar, OutFile);
_RarProcess.StartInfo = _startInfo;
_RarProcess.OutputDataReceived += new DataReceivedEventHandler(RarOutputHandler);
try
{
_RarProcess.Start();
//2009-06-23改为异步方式获取rar进程输出流
_RarProcess.BeginOutputReadLine();
//同步方式
//do
//{
// Thread.Sleep(800);
// string a = ReRarProcess.StandardOutput.ReadLine();
// if (a.Contains("完成") )
// {
// _RarProcess.Close();
// break;
//
// }
//}
//while (!ReRarProcess.StandardOutput.ReadLine().Contains("完成"));
}
catch (Exception ex)
{
if (_RarProcess != null)
{
_RarProcess.Close();
_RarProcess = null;
}
Log.WriteErLog(ex.Message);
}
finally
{
_isRunning = false;
}
}
private void BuildExe()
{
try
{
_ExeProcess.Start();
//2009-06-23改为异步方式获取rar进程输出流
_ExeProcess.BeginOutputReadLine();
//同步方式
//using (StreamReader sr = _rarProcess.StandardOutput)
//{
// string str = sr.ReadToEnd();
// while (!str.Contains("完成")) { Thread.Sleep(1); }
// if (!string.IsNullOrEmpty(str) && str.Contains("完成"))
// {
// sr.Close();
// _ExeProcess.Close();
// _RarThread.Start();
// }
//}
}
catch (Exception ex)
{
if (_ExeProcess != null)
{
_ExeProcess.Close();
_ExeProcess = null;
}
//MessageBox.Show(ex.Message + "\n" + "Are you sure rar.exe is here:" + "\n" + _startInfo.WorkingDirectory);
Log.WriteErLog(ex.Message);
}
finally
{
_isRunning = false;
}
}
public void Cancel()
{
try
{
if (_ExeProcess != null)
{
_ExeProcess.Kill();
}
if (_RarProcess != null)
{
_RarProcess.Kill();
}
}
catch
{
}
}
/// <summary>
/// 初始化Rar.exe所需自解压配置文件
/// </summary>
public void InitialRarConfig()
{
InitialRarConfig(Startupfile);
}
/// <summary>
/// 初始化自解压配置文件
/// </summary>
/// <param name="startupfile">rar生成exe内自动启动文件,默认为程序自动生成的swf文件</param>
public void InitialRarConfig(string _startupfile)
{
using (FileStream fs = new FileStream(m.UserDataPath + "\\" + _infofile, FileMode.Create))
{
using (StreamWriter sw = new StreamWriter(fs, Encoding.Default))
{
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine("Setup={0}", _startupfile);
sw.WriteLine("TempMode");
sw.WriteLine("Silent=1");
sw.WriteLine("Overwrite=1");
sw.Flush();
sw.Close();
}
}
}
public void Dispose()
{
if (_RarThread.ThreadState != System.Threading.ThreadState.Running)
{ _RarThread.Abort(); _RarThread = null; }
_ExeThread = null;
if (_ExeProcess != null) _ExeProcess.Dispose();
if (_RarProcess != null)
{
_RarProcess.Close();
_RarProcess.Dispose();
}
if (_startInfo != null) _startInfo = null;
if (m != null) m.Dispose();
}
}
}