0

I am a Jr. Programmer trying to get mp4 videos from an API and save them to a folder on the network. I am using the following code;

public static void saveVideos(HttpContent content, String filename, bool overwrite)
    {
        string pathName = Path.GetFullPath(filename);
        using (FileStream fs = new FileStream(pathName, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            if (fs.CanWrite)
            {
                byte[] buffer = Encoding.UTF8.GetBytes(content.ToString());
                fs.Write(buffer, 0, buffer.Length);
                fs.Flush();
                fs.Close();

            }
        }
    }

The code will compile without errors but all videos are written to the folder with a size of 1KB. I can't seem to figure out why I am not getting all of the file.

When I inspect the value of the content I see I am getting data that looks like this:

Headers = {Content-Length: 240634544
Content-Disposition: attachment; filename=Orders.dat
Content-Type: application/x-www-form-urlencoded; charset=utf-8

Can anyone point out my error here?

Thanks

abhilash
  • 5,605
  • 3
  • 36
  • 59
Perry
  • 1,277
  • 2
  • 17
  • 39
  • 1
    `HttpContent.ToString()` does not returns its content. You can use the `CopyToAsync` or `ReadAsStreamAsync` or `ReadAsStringAsync` methods. The documentation is here: https://msdn.microsoft.com/en-us/library/system.net.http.httpcontent(v=vs.118).aspx – Luke Vo Feb 26 '16 at 13:52
  • 1
    *if (fs.CanWrite)* is totally useless. You opened it for write, so clearly it `CanWrite` And the `Flush()` and `Close()` are useless too... You are using the `using` pattern so that you don't have to manually `Flush()` and `Close()` – xanatos Feb 26 '16 at 13:53
  • @DatVM reading as a string wouldn't make sense here, since he's downloading a video file which is a binary file. Using `ReadAsByteArrayAsync` (or `CopyToAsync` as you mentioned) is the way to go. – Phil K Feb 26 '16 at 13:55
  • @PhilK Yes, you're right, I forgot about that. – Luke Vo Feb 26 '16 at 14:04

2 Answers2

4

This doesn't do what you think it does:

content.ToString()

Unless otherwise overridden, the default implementation of .ToString() simply prints the name of the class. So all you're saving is a bunch of files with class names in them.

What you're probably looking for is the .ReadAsStringAsync() method instead. Or, since you're converting it to bytes anyway, .ReadAsByteArrayAsync() would also work. Perhaps something like this:

byte[] buffer = await content.ReadAsByteArrayAsync();

Of course, since this uses await then your method would have to be async:

public static async Task saveVideos(HttpContent content, String filename, bool overwrite)

If you can't make use of async and await (if you're on an older .NET version), then there are other ways to handle it as well.


Edit: Based on the comments and some of the context of the question, you may be dealing with large files here. In that case, using streams would perform a lot better. I don't have any sample code at the moment, but essentially what you'd want to do is move data directly from one stream to another rather than storing it in an in-memory variable.

Community
  • 1
  • 1
David
  • 208,112
  • 36
  • 198
  • 279
  • Thanks @David I have based on the comments I have changed to code to content. ReadAsByteArrayAsync and it is working. It is very slow on larger files. I tried your suggestion to use an async method with the await command but got an error stating cannot await a byte[]. – Perry Feb 26 '16 at 14:59
  • @Perry: If it's reading the entire file into memory then it could be pretty slow, yes. In that case you might try using using a stream instead: https://msdn.microsoft.com/en-us/library/hh138076.aspx It might take a little tinkering, but with that you should be able to move the bytes directly between two open streams (one from the HTTP response, one from the open file being written) without holding it in memory, which would be ideal. As for the error, I suspect you might not be using `await` correctly. You should be awaiting the task, not the result of the task. – David Feb 26 '16 at 15:03
0

If anyone else is having an issue or learning how to save a file using a FileStream hear is the code I used to solve the problem.

public static void saveVideos(HttpContent content, String filename, bool overwrite)
    {
        string pathName = Path.GetFullPath(filename);
        using (Stream fs = new FileStream(pathName, FileMode.Create, FileAccess.Write, FileShare.None, 4096, FileOptions.None))
        {
               byte[] buffer = content.ReadAsByteArrayAsync().Result;
               fs.Write(buffer, 0, buffer.Length);
        }
    }
Perry
  • 1,277
  • 2
  • 17
  • 39