Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File upload with c# and streaming

Looking at the different ways to upload a file in .NET, e.g. HttpPostedFile, and using a HttpHandler, I'm trying to understand how the process works in a bit more details.

Specifically how it writes the information to a file.

Say I have the following:

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

The actual file does not get created until the full stream seems to be processed.

Similarly:

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);
    }
}

I would have thought that this would "progressively" write the file as it reads the stream. Looking at the filesystem, it does not seems to do this at all. If I breakpoint inside the while, it does though.

What I'm trying to do, is have it so you upload a file (using a javascript uploader), and poll alongside, whereby the polling ajax request tries to get the fileinfo(file size) of the uploaded file every second. However, it always returns 0 until the upload is complete.

Vimeo seems to be able to do this type of functionality (for IE)?? Is this a .NET limitation, or is there a way to progressively write the file from the stream?

like image 934
mickyjtwin Avatar asked Oct 22 '25 00:10

mickyjtwin


1 Answers

Two points:

First, in Windows, the displayed size of a file is not updated constantly. The file might indeed be growing continually, but the size only increases once.

Second (more likely in this case), the stream might not be flushing to the disk. You could force it to by adding output.Flush() after the call to output.Write(). You might not want to do that, though, since it will probably have a negative impact on performance.

Perhaps you could poll the Length property of the output stream directly, instead of going through the file system.

EDIT:

To make the Length property of the stream accessible to other threads, you could have a field in your class and update it with each read/write:

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;
}
like image 68
phoog Avatar answered Oct 23 '25 12:10

phoog