WinSCP 没有完全从 C# 使用 System.Diagnostics.Process 执行?
WinSCP not fully executing from C# using System.Diagnostics.Process?
我正在尝试从 FTP 服务器下载一些文件并自动执行此任务。我大部分时间都遵循本教程来完成我的过程:
http://www.timmitchell.net/post/2015/08/03/downloading-sftp-files-with-ssis/
现在,我想使用命令:
synchronize local \somesharefolder /someremotedir
如果我 运行 从我的命令行输入这个命令,它可以正常工作并同步 300~ 个必要的文件。
我的问题是,当我从 C# 运行 执行此操作时,它仅同步 30~ 个文件并在 WaitForExit()
函数调用中挂起。如果我显示进程 window 并手动关闭它,我的输出没有显示任何错误。连接成功,文件开始下载,然后停止。
这是编辑后的代码:
// Create a new Process object to execute WinSCP
Process winscp = new Process();
// Set the executable path and download directory
winscp.StartInfo.FileName = @"C:\Program Files (x86)\WinSCP\WinSCP.com";
// Set static execution options
winscp.StartInfo.UseShellExecute = false;
winscp.StartInfo.RedirectStandardInput = true;
winscp.StartInfo.RedirectStandardOutput = true;
winscp.StartInfo.CreateNoWindow = true;
// Set session options
string sessionOptionString = "option batch abort" +
System.Environment.NewLine + "option confirm off";
// Build the connection string (<user>:<password>@<hostname>)
string connectString = @"open ftp://" +
"username" + ":" +
"password" + "@" +
"hostURL" + " -implicit";
// Supplying the host key adds an extra level of security, and avoids getting the prompt to trust the server
string hostKeyString = null;
// If hostkey was specified, include it
if (hostKeyString != null && hostKeyString.Length > 0)
{
connectString += " -hostkey=\"" + hostKeyString + "\"";
}
else
{
connectString += " -hostkey";
}
// Build the get command strings, stored in list to maintain order.
List<string> cmdStrings = new List<string>();
cmdStrings.Add(@"synchronize local \some\file\share /some/remote/directory");
// Create output variables to capture execution info
string outStr = "", errStr = "";
int returnVal = 1;
// This try/catch block will capture catastrophic failures (such as specifying the wrong path to winscp)
try
{
winscp.Start();
winscp.StandardInput.WriteLine(sessionOptionString);
winscp.StandardInput.WriteLine(connectString);
foreach (var cmd in cmdStrings)
{
winscp.StandardInput.WriteLine(cmd);
}
winscp.StandardInput.Close();
winscp.WaitForExit();
// Set the outStr to the output value, obfuscating the password
outStr = winscp.StandardOutput.ReadToEnd().Replace(":" +
"password" +
"@", ":*******@");
returnVal = winscp.ExitCode;
}
catch (Exception ex)
{
errStr = "An error occurred when attempting to execute winscp.com: " +
ex.Message.Replace("'", "\"").Replace("--", " - ");
}
outStr.Dump();
示例编辑输出:
winscp> option batch abort
batch abort
reconnecttime 120
winscp> option confirm off
confirm off
winscp> open ftp://something:*******@127.0.0.1 -implicit -hostkey
Connecting to 127.0.0.1:990 ...
TLS connection established. Waiting for welcome message...
Connected
Starting the session...
Session started.
Active session: [1] something@127.0.0.1
winscp> synchronize local \some\file\share /some/remote/directory
Comparing...
Local '\some\file\share' <= Remote '/some/remote/directory'
Synchronizing...
Local '\some\file\share' <= Remote '/some/remote/directory'
something150401.csv | 0 B | 0.0 KB/s | binary | 0%
something150402.csv | 0 B | 0.0 KB/s | binary | 0%
something150403.csv | 81 B | 0.1 KB/s | binary | 100%
something150404.csv | 121 B | 0.2 KB/s | binary | 100%
something150405.csv | 242 B | 0.3 KB/s | binary | 100%
something150406.csv | 164 B | 0.1 KB/s | binary | 100%
something150407.csv | 39 B | 0.1 KB/s | binary | 100%
something150408.csv | 203 B | 0.1 KB/s | binary | 100%
something150409.csv | 197 B | 0.2 KB/s | binary | 100%
something150410.csv | 0 B | 0.2 KB/s | binary | 0%
something150411.csv | 124 B | 0.2 KB/s | binary | 100%
something150412.csv | 202 B | 0.2 KB/s | binary | 100%
something150413.csv | 123 B | 0.2 KB/s | binary | 100%
something150414.csv | 199 B | 0.2 KB/s | binary | 100%
something150415.csv | 283 B | 0.2 KB/s | binary | 100%
something150416.csv | 203 B | 0.2 KB/s | binary | 100%
something150417.csv | 82 B | 0.2 KB/s | binary | 100%
something150418.csv | 199 B | 0.3 KB/s | binary | 100%
something150419.csv | 285 B | 0.3 KB/s | binary | 100%
something150420.csv | 82 B | 0.3 KB/s | binary | 100%
something150421.csv | 156 B | 0.3 KB/s | binary | 100%
something150422.csv | 162 B | 0.3 KB/s | binary | 100%
something150423.csv | 163 B | 0.3 KB/s | binary | 100%
something150424.csv | 204 B | 0.3 KB/s | binary | 100%
something150425.csv | 240 B | 0.3 KB/s | binary | 100%
something150426.csv | 82 B | 0.3 KB/s | binary | 100%
something150427.csv | 164 B | 0.3 KB/s | binary | 100%
something150428.csv | 122 B | 0.3 KB/s | binary | 100%
something150429.csv | 82 B | 0.3 KB/s | binary | 100%
something150430.csv | 0 B | 0.3 KB/s | binary | 0%
something150501.csv | 123 B | 0.3 KB/s | binary | 100%
something150502.csv | 122 B | 0.3 KB/s | binary | 100%
something150503.csv | 245 B | 0.3 KB/s | binary | 100%
something150504.csv | 203 B | 0.4 KB/s | binary | 100%
something150505.csv | 205 B | 0.5 KB/s | binary | 100%
something150506.csv | 121 B | 0.5 KB/s | binary | 100%
something150507.csv | 164 B | 0.5 KB/s | binary | 100%
something150508.csv | 82 B | 0.5 KB/s | binary | 100%
something150509.csv | 164 B | 0.5 KB/s | binary | 100%
something150510.csv | 205 B | 0.5 KB/s | binary | 100%
something150511.csv | 164 B | 0.5 KB/s | binary | 100%
something150512.csv | 41 B | 0.5 KB/s | binary | 100%
something150513.csv | 0 B | 0.5 KB/s | binary | 0%
something150514.csv | 82 B | 0.5 KB/s | binary | 100%
something150515.csv | 82 B | 0.5 KB/s | binary | 100%
something150516.csv | 244 B | 0.5 KB/s | binary | 100%
输出到此为止,并没有被切断。
您正在等待进程完成,然后再阅读 StandardOutput
。这是有问题的,因为重定向的 StandardOutput
有一个 fixed-size buffer。
当缓冲区已满时,写入它会阻塞,因此 Process
管理的 child-process 在写入其 stdout
时阻塞。
如果您在 WaitForExit
之前 ReadToEnd
,问题应该不会再发生。
我正在尝试从 FTP 服务器下载一些文件并自动执行此任务。我大部分时间都遵循本教程来完成我的过程:
http://www.timmitchell.net/post/2015/08/03/downloading-sftp-files-with-ssis/
现在,我想使用命令:
synchronize local \somesharefolder /someremotedir
如果我 运行 从我的命令行输入这个命令,它可以正常工作并同步 300~ 个必要的文件。
我的问题是,当我从 C# 运行 执行此操作时,它仅同步 30~ 个文件并在 WaitForExit()
函数调用中挂起。如果我显示进程 window 并手动关闭它,我的输出没有显示任何错误。连接成功,文件开始下载,然后停止。
这是编辑后的代码:
// Create a new Process object to execute WinSCP
Process winscp = new Process();
// Set the executable path and download directory
winscp.StartInfo.FileName = @"C:\Program Files (x86)\WinSCP\WinSCP.com";
// Set static execution options
winscp.StartInfo.UseShellExecute = false;
winscp.StartInfo.RedirectStandardInput = true;
winscp.StartInfo.RedirectStandardOutput = true;
winscp.StartInfo.CreateNoWindow = true;
// Set session options
string sessionOptionString = "option batch abort" +
System.Environment.NewLine + "option confirm off";
// Build the connection string (<user>:<password>@<hostname>)
string connectString = @"open ftp://" +
"username" + ":" +
"password" + "@" +
"hostURL" + " -implicit";
// Supplying the host key adds an extra level of security, and avoids getting the prompt to trust the server
string hostKeyString = null;
// If hostkey was specified, include it
if (hostKeyString != null && hostKeyString.Length > 0)
{
connectString += " -hostkey=\"" + hostKeyString + "\"";
}
else
{
connectString += " -hostkey";
}
// Build the get command strings, stored in list to maintain order.
List<string> cmdStrings = new List<string>();
cmdStrings.Add(@"synchronize local \some\file\share /some/remote/directory");
// Create output variables to capture execution info
string outStr = "", errStr = "";
int returnVal = 1;
// This try/catch block will capture catastrophic failures (such as specifying the wrong path to winscp)
try
{
winscp.Start();
winscp.StandardInput.WriteLine(sessionOptionString);
winscp.StandardInput.WriteLine(connectString);
foreach (var cmd in cmdStrings)
{
winscp.StandardInput.WriteLine(cmd);
}
winscp.StandardInput.Close();
winscp.WaitForExit();
// Set the outStr to the output value, obfuscating the password
outStr = winscp.StandardOutput.ReadToEnd().Replace(":" +
"password" +
"@", ":*******@");
returnVal = winscp.ExitCode;
}
catch (Exception ex)
{
errStr = "An error occurred when attempting to execute winscp.com: " +
ex.Message.Replace("'", "\"").Replace("--", " - ");
}
outStr.Dump();
示例编辑输出:
winscp> option batch abort
batch abort
reconnecttime 120
winscp> option confirm off
confirm off
winscp> open ftp://something:*******@127.0.0.1 -implicit -hostkey
Connecting to 127.0.0.1:990 ...
TLS connection established. Waiting for welcome message...
Connected
Starting the session...
Session started.
Active session: [1] something@127.0.0.1
winscp> synchronize local \some\file\share /some/remote/directory
Comparing...
Local '\some\file\share' <= Remote '/some/remote/directory'
Synchronizing...
Local '\some\file\share' <= Remote '/some/remote/directory'
something150401.csv | 0 B | 0.0 KB/s | binary | 0%
something150402.csv | 0 B | 0.0 KB/s | binary | 0%
something150403.csv | 81 B | 0.1 KB/s | binary | 100%
something150404.csv | 121 B | 0.2 KB/s | binary | 100%
something150405.csv | 242 B | 0.3 KB/s | binary | 100%
something150406.csv | 164 B | 0.1 KB/s | binary | 100%
something150407.csv | 39 B | 0.1 KB/s | binary | 100%
something150408.csv | 203 B | 0.1 KB/s | binary | 100%
something150409.csv | 197 B | 0.2 KB/s | binary | 100%
something150410.csv | 0 B | 0.2 KB/s | binary | 0%
something150411.csv | 124 B | 0.2 KB/s | binary | 100%
something150412.csv | 202 B | 0.2 KB/s | binary | 100%
something150413.csv | 123 B | 0.2 KB/s | binary | 100%
something150414.csv | 199 B | 0.2 KB/s | binary | 100%
something150415.csv | 283 B | 0.2 KB/s | binary | 100%
something150416.csv | 203 B | 0.2 KB/s | binary | 100%
something150417.csv | 82 B | 0.2 KB/s | binary | 100%
something150418.csv | 199 B | 0.3 KB/s | binary | 100%
something150419.csv | 285 B | 0.3 KB/s | binary | 100%
something150420.csv | 82 B | 0.3 KB/s | binary | 100%
something150421.csv | 156 B | 0.3 KB/s | binary | 100%
something150422.csv | 162 B | 0.3 KB/s | binary | 100%
something150423.csv | 163 B | 0.3 KB/s | binary | 100%
something150424.csv | 204 B | 0.3 KB/s | binary | 100%
something150425.csv | 240 B | 0.3 KB/s | binary | 100%
something150426.csv | 82 B | 0.3 KB/s | binary | 100%
something150427.csv | 164 B | 0.3 KB/s | binary | 100%
something150428.csv | 122 B | 0.3 KB/s | binary | 100%
something150429.csv | 82 B | 0.3 KB/s | binary | 100%
something150430.csv | 0 B | 0.3 KB/s | binary | 0%
something150501.csv | 123 B | 0.3 KB/s | binary | 100%
something150502.csv | 122 B | 0.3 KB/s | binary | 100%
something150503.csv | 245 B | 0.3 KB/s | binary | 100%
something150504.csv | 203 B | 0.4 KB/s | binary | 100%
something150505.csv | 205 B | 0.5 KB/s | binary | 100%
something150506.csv | 121 B | 0.5 KB/s | binary | 100%
something150507.csv | 164 B | 0.5 KB/s | binary | 100%
something150508.csv | 82 B | 0.5 KB/s | binary | 100%
something150509.csv | 164 B | 0.5 KB/s | binary | 100%
something150510.csv | 205 B | 0.5 KB/s | binary | 100%
something150511.csv | 164 B | 0.5 KB/s | binary | 100%
something150512.csv | 41 B | 0.5 KB/s | binary | 100%
something150513.csv | 0 B | 0.5 KB/s | binary | 0%
something150514.csv | 82 B | 0.5 KB/s | binary | 100%
something150515.csv | 82 B | 0.5 KB/s | binary | 100%
something150516.csv | 244 B | 0.5 KB/s | binary | 100%
输出到此为止,并没有被切断。
您正在等待进程完成,然后再阅读 StandardOutput
。这是有问题的,因为重定向的 StandardOutput
有一个 fixed-size buffer。
当缓冲区已满时,写入它会阻塞,因此 Process
管理的 child-process 在写入其 stdout
时阻塞。
如果您在 WaitForExit
之前 ReadToEnd
,问题应该不会再发生。