文件上传进度
我一直在尝试跟踪文件上传的进度,但始终陷入死胡同(从 C# 应用程序而不是网页上传)。
我尝试使用 WebClient
如下:
class Program
{
static volatile bool busy = true;
static void Main(string[] args)
{
WebClient client = new WebClient();
// Add some custom header information
client.Credentials = new NetworkCredential("username", "password");
client.UploadProgressChanged += client_UploadProgressChanged;
client.UploadFileCompleted += client_UploadFileCompleted;
client.UploadFileAsync(new Uri("http://uploaduri/"), "filename");
while (busy)
{
Thread.Sleep(100);
}
Console.WriteLine("Done: press enter to exit");
Console.ReadLine();
}
static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
{
busy = false;
}
static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
Console.WriteLine("Completed {0} of {1} bytes", e.BytesSent, e.TotalBytesToSend);
}
}
文件确实上传并打印了进度,但进度比实际上传快得多,并且上传大文件时进度将在几秒钟内达到最大值但实际上传需要几分钟(不仅仅是等待响应,所有数据还没有到达服务器)。
因此,我尝试使用 HttpWebRequest
来传输数据(我知道这并不完全等同于文件上传,因为它不会生成 multipart/form-data
内容,但它确实可以说明我的问题)。我设置了AllowWriteStreamBuffering = false
并按照此问题/答案:
class Program
{
static void Main(string[] args)
{
FileInfo fileInfo = new FileInfo(args[0]);
HttpWebRequest client = (HttpWebRequest)WebRequest.Create(new Uri("http://uploadUri/"));
// Add some custom header info
client.Credentials = new NetworkCredential("username", "password");
client.AllowWriteStreamBuffering = false;
client.ContentLength = fileInfo.Length;
client.Method = "POST";
long fileSize = fileInfo.Length;
using (FileStream stream = fileInfo.OpenRead())
{
using (Stream uploadStream = client.GetRequestStream())
{
long totalWritten = 0;
byte[] buffer = new byte[3000];
int bytesRead = 0;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
uploadStream.Write(buffer, 0, bytesRead);
uploadStream.Flush();
Console.WriteLine("{0} of {1} written", totalWritten += bytesRead, fileSize);
}
}
}
Console.WriteLine("Done: press enter to exit");
Console.ReadLine();
}
}
直到整个文件已写入流并且在启动时已显示完整进度后,请求才会启动(我使用 fiddler 来验证这一点)。我还尝试将 SendChunked
设置为 true(也设置和不设置 ContentLength
)。看起来数据在通过网络发送之前仍然被缓存。
这些方法之一是否有问题,或者是否有另一种方法可以跟踪 Windows 应用程序文件上传的进度?
I've been trying to track the progress of a file upload but keep on ending up at dead ends (uploading from a C# application not a webpage).
I tried using the WebClient
as such:
class Program
{
static volatile bool busy = true;
static void Main(string[] args)
{
WebClient client = new WebClient();
// Add some custom header information
client.Credentials = new NetworkCredential("username", "password");
client.UploadProgressChanged += client_UploadProgressChanged;
client.UploadFileCompleted += client_UploadFileCompleted;
client.UploadFileAsync(new Uri("http://uploaduri/"), "filename");
while (busy)
{
Thread.Sleep(100);
}
Console.WriteLine("Done: press enter to exit");
Console.ReadLine();
}
static void client_UploadFileCompleted(object sender, UploadFileCompletedEventArgs e)
{
busy = false;
}
static void client_UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
Console.WriteLine("Completed {0} of {1} bytes", e.BytesSent, e.TotalBytesToSend);
}
}
The file does upload and progress is printed out but the progress is much faster than the actual upload and when uploading a large file the progress will reach the maximum within a few seconds but the actual upload takes a few minutes (it is not just waiting on a response, all the data have not yet arrived at the server).
So I tried using HttpWebRequest
to stream the data instead (I know this is not the exact equivalent of a file upload as it does not produce multipart/form-data
content but it does serve to illustrate my problem). I set AllowWriteStreamBuffering = false
and set the ContentLength
as suggested by this question/answer:
class Program
{
static void Main(string[] args)
{
FileInfo fileInfo = new FileInfo(args[0]);
HttpWebRequest client = (HttpWebRequest)WebRequest.Create(new Uri("http://uploadUri/"));
// Add some custom header info
client.Credentials = new NetworkCredential("username", "password");
client.AllowWriteStreamBuffering = false;
client.ContentLength = fileInfo.Length;
client.Method = "POST";
long fileSize = fileInfo.Length;
using (FileStream stream = fileInfo.OpenRead())
{
using (Stream uploadStream = client.GetRequestStream())
{
long totalWritten = 0;
byte[] buffer = new byte[3000];
int bytesRead = 0;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
{
uploadStream.Write(buffer, 0, bytesRead);
uploadStream.Flush();
Console.WriteLine("{0} of {1} written", totalWritten += bytesRead, fileSize);
}
}
}
Console.WriteLine("Done: press enter to exit");
Console.ReadLine();
}
}
The request does not start until the entire file have been written to the stream and already shows full progress at the time it starts (I'm using fiddler to verify this). I also tried setting SendChunked
to true (with and without setting the ContentLength
as well). It seems like the data still gets cached before being sent over the network.
Is there something wrong with one of these approaches or is there perhaps another way I can track the progress of file uploads from a windows application?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
更新:
这个控制台应用程序按预期为我工作:
Updated:
This console app works for me as expected:
我相信您的请求正在通过网络进行传输。我发现 Fiddler 2.3.4.4 不显示部分请求,但 MS网络监视器可以显示各个数据包,但不能显示本地主机环回(因此如果您想验证,服务器和客户端需要位于不同的计算机上)。
我在此处遇到了相同的隐藏缓冲问题,并相信其中之一服务器上未正确设置用于流式传输的 WCF 服务设置。我很好奇您正在实现什么类型的 Web 服务、绑定等。本质上,服务器会缓冲整个消息,然后将其交给处理,这就是为什么在从客户端发送最后一个字节后可能会看到很大的延迟。
对于我正在查看的 Web 服务是 WCF REST 服务的情况,文件在作为流参数传递给 Web 服务方法之前在以下位置进行缓冲:
I believe your request is going over the network. I've discovered Fiddler 2.3.4.4 does not show partial requests but the MS Network Monitor can show the individual packets however not on the localhost loopback (so server and client need to be on different machines if you wish to verify).
I'm running into the same hidden buffering issue here and believe that one of the WCF service settings is not set up correctly on the server for streaming. I'm curious what type of web service you are implementing, bindings, etc. Essentially the server buffers the entire message then hands it off for processing which is why one might see a large delay after the last byte is sent from the client.
For a case I was looking at where the web service was a WCF REST service the file was being buffered at the following location before being passed as a stream argument to a web service method: