我有一个 C# 代码,其中我需要运行一个非常旧的供应商二进制到 ASCII 转换程序,这是我的代码的相关部分:
这些代码在 30 分钟计时器内连续运行。每天大约有 50 到 150 个文件需要转换,但是每天一次,输入文件名的行会收到“访问被拒绝...”错误,仅一次,重新启动我的 C# 代码后,转换就会恢复很好。
当我在办公室时,它永远不会损坏,只有当我不在办公室时,它才会损坏。我调整了这条线之前的等待时间,但没有效果。
我有点不知道如何解决这个问题。感谢您的建议和帮助。
您可以尝试使用不同的方式将数据发送到StandardInput。下面我将展示一些不同的方法来写入StandardInput和从StandardOutput读取。该代码已使用 .NET Framework v4.8 进行了测试。文章末尾是我用于测试的控制台应用程序的代码。
注意:在下面的代码中,确保将响应更改为所需的值。
添加以下 using 指令
using System.Diagnostics;
using System.IO;
选项1:
private void RunProcess(string exeFilename)
{
ProcessStartInfo startInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
FileName = exeFilename,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden
};
using (Process p = new Process() { StartInfo = startInfo, EnableRaisingEvents = true })
{
//subscribe to event and add event handler code
p.ErrorDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Error: " + e.Data);
}
};
//subscribe to event and add event handler code
p.OutputDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Output: " + e.Data);
}
};
//start
p.Start();
p.BeginErrorReadLine(); //begin async reading for standard error
p.BeginOutputReadLine(); //begin async reading for standard output
using (StreamWriter sw = p.StandardInput)
{
//response for 1st prompt
sw.WriteLine(@"C:\Temp\Test.txt");
//response for 2nd prompt
sw.WriteLine("n");
//response for 3rd prompt
sw.WriteLine("y");
//response for 4th prompt
//sw.WriteLine("y");
sw.WriteLine("");
}
//waits until the process is finished before continuing
p.WaitForExit();
}
}
选项2:
注意:响应被放入List中,然后使用foreach循环写入StandardInput。
private void RunProcess(string exeFilename)
{
ProcessStartInfo startInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
FileName = exeFilename,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden
};
using (Process p = new Process() { StartInfo = startInfo, EnableRaisingEvents = true })
{
//subscribe to event and add event handler code
p.ErrorDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Error: " + e.Data);
}
};
//subscribe to event and add event handler code
p.OutputDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Output: " + e.Data);
}
};
//start
p.Start();
p.BeginErrorReadLine(); //begin async reading for standard error
p.BeginOutputReadLine(); //begin async reading for standard output
using (StreamWriter sw = p.StandardInput)
{
//provide values for each input prompt
//ToDo: add values for each input prompt
List<string> responses = new List<string>() { @"c:\Temp\Test.txt", "n", "y", string.Empty };
foreach (string resp in responses)
{
sw.WriteLine(resp);
}
}
//waits until the process is finished before continuing
p.WaitForExit();
}
}
选项3:
注意:此选项使用Task(或Thread)从StandardOutput读取。这允许人们读取不以换行符结尾的StandardOutput,以及包含换行符的输出。如果 .exe 文件的输出不以换行符结尾,请尝试此选项以查看它是否提供所需的输出。
private CancellationTokenSource _tokenSource;
private CancellationToken _token;
...
private async void ReadStandardOutput(Stream s, CancellationToken token)
{
int bufferSize = 1024;
int totalBytesRead = 0;
while(true)
{
if (token.IsCancellationRequested)
return;
byte[] buffer = new byte[bufferSize];
int bytesRead = await s.ReadAsync(buffer, 0, bufferSize, token);
//add
totalBytesRead += bytesRead;
if (bytesRead > 0)
{
//convert to string
string output = Encoding.ASCII.GetString(buffer, 0, bytesRead).Trim();
//Debug.WriteLine($"StandardOutput: '{output}'");
Debug.WriteLine($"{output}");
}
}
}
private void RunProcess(string exeFilename)
{
//create new instance
_tokenSource = new CancellationTokenSource();
//create reference
_token = _tokenSource.Token;
ProcessStartInfo startInfo = new ProcessStartInfo()
{
CreateNoWindow = true,
FileName = exeFilename,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden
};
using (Process p = new Process() { StartInfo = startInfo, EnableRaisingEvents = true })
{
//subscribe to event and add event handler code
p.ErrorDataReceived += (sender, e) =>
{
if (!String.IsNullOrEmpty(e.Data))
{
//ToDo: add desired code
Debug.WriteLine("Error: " + e.Data);
}
};
p.Exited += (sender, e) =>
{
//cancel reading from StandardOutput
_tokenSource.Cancel();
Debug.WriteLine("Process has exited.");
};
//start
p.Start();
p.BeginErrorReadLine(); //begin async reading for standard error
Task.Factory.StartNew(() => ReadStandardOutput(p.StandardOutput.BaseStream, _token));
//Thread t = new Thread(() => ReadStandardOutput(p.StandardOutput.BaseStream, _token)) { IsBackground = true };
//t.Start();
//sleep to allow time for task/thread to start
System.Threading.Thread.Sleep(200);
using (StreamWriter sw = p.StandardInput)
{
//provide values for each input prompt
//ToDo: add values for each input prompt
List<string> responses = new List<string>() { @"c:\Temp\Test.txt", "n", "y", string.Empty };
foreach (string resp in responses)
{
sw.WriteLine(resp);
//System.Threading.Thread.Sleep(200);
}
}
//waits until the process is finished before continuing
p.WaitForExit();
Debug.WriteLine("After p.WaitForExit");
}
}
用法:
RunProcess(@"C:\Temp\ConsoleInputTest.exe");
为了测试,我创建了一个 控制台应用程序(.NET Framework)(名称:ConsoleInputTest)
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace ConsoleInputTest
{
internal class Program
{
static void Main(string[] args)
{
Dictionary<string, string> flagsDict = null;
if (args.Length != 0)
{
//get command-line args and put them in a Dictionary
flagsDict = GetCommandLineArgs(args);
}
else
{
//create new instance
flagsDict = new Dictionary<string, string>();
string filename = string.Empty;
do
{
//prompt user
Console.Write("Please enter filename: ");
//read input
filename = Console.ReadLine();
if (!File.Exists(filename))
Console.Error.WriteLine($"File doesn't exist ('{filename}'). ");
} while (!File.Exists(filename));
flagsDict.Add("filename", filename);
string prompt2 = GetYesNoAnswer("Prompt2 - For testing, please enter 'n' for this prompt (default: y)");
flagsDict.Add("prompt2", prompt2);
string prompt3 = GetYesNoAnswer("Prompt3 - For testing, please press enter or enter 'y' for this prompt (default: y)");
flagsDict.Add("prompt3", prompt3);
string prompt4 = GetYesNoAnswer("Prompt4 - For testing, please press enter or enter 'y' for this prompt (default: y)");
flagsDict.Add("prompt4", prompt4);
}
if (flagsDict != null)
{
//for testing, output arguments/input and values
foreach (KeyValuePair<string, string> kvp in flagsDict)
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}
}
}
private static string GetYesNoAnswer(string message)
{
string result = string.Empty;
do
{
Console.Write($"{message}: ");
result = Console.ReadLine();
if (String.IsNullOrWhiteSpace(result))
result = "y";
if (result.ToLower() != "y" && result.ToLower() != "yes" && result.ToLower() != "n" && result.ToLower() != "no")
Console.Error.WriteLine("Invalid response. ");
} while (result.ToLower() != "y" && result.ToLower() != "yes" && result.ToLower() != "n" && result.ToLower() != "no");
return result;
}
private static void DisplayUsage()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat($"{Environment.NewLine}");
sb.AppendFormat($" Usage 1:{Environment.NewLine}");
sb.AppendFormat($" {System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.exe{Environment.NewLine}");
sb.AppendFormat($"{Environment.NewLine}");
sb.AppendFormat($" Usage 2:{Environment.NewLine}");
sb.AppendFormat($" {System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.exe <flag> <value>{Environment.NewLine}");
sb.AppendFormat($"{Environment.NewLine}");
sb.AppendFormat($" Flags: {Environment.NewLine}");
sb.AppendFormat($"{Environment.NewLine}");
sb.AppendFormat($@" -filename: <filename> (ex: -filename: ""C:\My Folder\filename1.txt"") {Environment.NewLine}");
sb.AppendFormat($@" -prompt2: [y|n] (ex: -prompt2: n) {Environment.NewLine}");
sb.AppendFormat($@" -prompt3: [y|n] (ex: -prompt3: y) {Environment.NewLine}");
sb.AppendFormat($@" -prompt4: [y|n] (ex: -prompt4: y) {Environment.NewLine}");
Console.WriteLine(sb.ToString());
}
private static Dictionary<string, string> GetCommandLineArgs(string[] args)
{
Dictionary<string, string> flagsDict = new Dictionary<string, string>();
string currentFlag = string.Empty;
//the following retrieves the command-line arguments
//it handles values that contain spaces
//such as 'C:\My Folder\filename1.exe'
for (int i = 0; i < args.Length; i++)
{
//get flag
//ex: '-f:'
if (args[i].StartsWith("-"))
{
//this keeps track of the current flag which
//is necessary in order to handle values that contain spaces
if (!args[i].EndsWith(":"))
{
//set value; if flag doesn't end with ':', add it
currentFlag = $"{args[i]}:";
}
else
{
//set value
currentFlag = args[i];
}
if (!flagsDict.ContainsKey(currentFlag))
{
//add to Dictionary
flagsDict.Add(currentFlag, string.Empty);
}
else
{
Console.Error.WriteLine($"Error: '{currentFlag}' already specified. A flag is only permitted to be specified once.");
Environment.Exit(-1);
}
}
else if (args[i] == "/?")
{
DisplayUsage();
}
else
{
//if no flag is specified, assume it's a filename
if (String.IsNullOrEmpty(currentFlag))
{
currentFlag = "-f:"; //filename
flagsDict.Add(currentFlag, args[i]); //add to Dictionary
}
else if (flagsDict.ContainsKey(currentFlag))
{
if (!String.IsNullOrEmpty(flagsDict[currentFlag]))
flagsDict[currentFlag] += " "; //add space
flagsDict[currentFlag] += args[i]; //set or update value in Dictionary
}
}
}
return flagsDict;
}
}
}
资源: