How do I save a stream to a file in C#?

后端 未结 10 2270
我寻月下人不归
我寻月下人不归 2020-11-22 03:06

I have a StreamReader object that I initialized with a stream, now I want to save this stream to disk (the stream may be a .gif or .jpg

10条回答
  •  [愿得一人]
    2020-11-22 04:04

    I don't get all of the answers using CopyTo, where maybe the systems using the app might not have been upgraded to .NET 4.0+. I know some would like to force people to upgrade, but compatibility is also nice, too.

    Another thing, I don't get using a stream to copy from another stream in the first place. Why not just do:

    byte[] bytes = myOtherObject.InputStream.ToArray();
    

    Once you have the bytes, you can easily write them to a file:

    public static void WriteFile(string fileName, byte[] bytes)
    {
        string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (!path.EndsWith(@"\")) path += @"\";
    
        if (File.Exists(Path.Combine(path, fileName)))
            File.Delete(Path.Combine(path, fileName));
    
        using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write))
        {
            fs.Write(bytes, 0, (int)bytes.Length);
            //fs.Close();
        }
    }
    

    This code works as I've tested it with a .jpg file, though I admit I have only used it with small files (less than 1 MB). One stream, no copying between streams, no encoding needed, just write the bytes! No need to over-complicate things with StreamReader if you already have a stream you can convert to bytes directly with .ToArray()!

    Only potential downsides I can see in doing it this way is if there's a large file you have, having it as a stream and using .CopyTo() or equivalent allows FileStream to stream it instead of using a byte array and reading the bytes one by one. It might be slower doing it this way, as a result. But it shouldn't choke since the .Write() method of the FileStream handles writing the bytes, and it's only doing it one byte at a time, so it won't clog memory, except that you will have to have enough memory to hold the stream as a byte[] object. In my situation where I used this, getting an OracleBlob, I had to go to a byte[], it was small enough, and besides, there was no streaming available to me, anyway, so I just sent my bytes to my function, above.

    Another option, using a stream, would be to use it with Jon Skeet's CopyStream function that was in another post - this just uses FileStream to take the input stream and create the file from it directly. It does not use File.Create, like he did (which initially seemed to be problematic for me, but later found it was likely just a VS bug...).

    /// 
    /// Copies the contents of input to output. Doesn't close either stream.
    /// 
    public static void CopyStream(Stream input, Stream output)
    {
        byte[] buffer = new byte[8 * 1024];
        int len;
        while ( (len = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            output.Write(buffer, 0, len);
        }    
    }
    
    public static void WriteFile(string fileName, Stream inputStream)
    {
        string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
        if (!path.EndsWith(@"\")) path += @"\";
    
        if (File.Exists(Path.Combine(path, fileName)))
            File.Delete(Path.Combine(path, fileName));
    
        using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write)
        {
            CopyStream(inputStream, fs);
        }
    
        inputStream.Close();
        inputStream.Flush();
    }
    

提交回复
热议问题