使用C#进行文件上传和流式传输

4

在.NET中上传文件的不同方法,例如HttpPostedFile和使用HttpHandler,我正在尝试更详细地了解该过程的工作原理。

具体来说,它如何将信息写入文件中。

假设我有以下内容:

HttpPostedFile file = context.Request.Files[0];
file.SaveAs("c:\temp\file.zip");

实际文件直到完整流程被处理之后才会创建。
同样地:
using (Stream output = File.OpenWrite("c:\temp\file.zip"))
using (Stream input = file.InputStream)
{
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
    {
        output.Write(buffer, 0, bytesRead);
    }
}

我本以为这个操作会在读取流的同时“逐渐”写入文件。但是查看文件系统,它似乎并没有这样做。如果我在 while 循环内设置断点,则会执行该操作。
我的目标是实现上传文件(使用 JavaScript 上传工具)的同时进行轮询,每秒钟轮询一次 ajax 请求以尝试获取已上传文件的文件信息(文件大小)。然而,在上传完成之前,它始终返回 0。
Vimeo 似乎能够在 IE 上实现此类功能?是 .NET 的限制,还是有一种方法可以从流中逐步写入文件?
1个回答

3
两点说明:
首先,在Windows中,文件的显示大小不会持续更新。文件可能确实在持续增长,但是大小只会增加一次。
其次(在这种情况下更有可能),流可能没有刷新到磁盘。您可以在调用output.Write()后添加output.Flush()来强制刷新它。然而,由于它可能对性能产生负面影响,您可能不想这样做。
也许您可以直接轮询输出流的Length 属性,而无需通过文件系统。
编辑:
为了使流的Length属性可被其他线程访问,您可以在类中创建一个字段,并在每次读/写时更新它。
private long _uploadedByteCount;

void SomeMethod()
{
    using (Stream output = File.OpenWrite("c:\temp\file.zip"))
    using (Stream input = file.InputStream)
    {
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            output.Write(buffer, 0, bytesRead);
            Interlocked.Add(ref _uploadedByteCount, bytesRead);
        }
    }
}

public long GetUploadedByteCount()
{
    return _uploadedByteCount;
}

你的第二点是正确的,如果我将缓冲区大小设置得足够低,并刷新,它确实会写入,但正如你所提到的,这样做的性能影响不会很好。经过查看YouTube和Vimeo,它们在IE中似乎都是做同样的事情,即它们发送一个流式帖子文件,并使用JavaScript轮询大小更新。想知道他们可能是如何做到的? - mickyjtwin
@mickyjtwin 很难说。也许你可以在一个字段中保留字节计数,然后通过属性或方法将其暴露给 JavaScript。我已经添加了一个使用方法的示例。 - phoog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接