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

后端 未结 10 2219
我寻月下人不归
我寻月下人不归 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 03:45
    //If you don't have .Net 4.0  :)
    
    public void SaveStreamToFile(Stream stream, string filename)
    {  
       using(Stream destination = File.Create(filename))
          Write(stream, destination);
    }
    
    //Typically I implement this Write method as a Stream extension method. 
    //The framework handles buffering.
    
    public void Write(Stream from, Stream to)
    {
       for(int a = from.ReadByte(); a != -1; a = from.ReadByte())
          to.WriteByte( (byte) a );
    }
    
    /*
    Note, StreamReader is an IEnumerable<Char> while Stream is an IEnumbable<byte>.
    The distinction is significant such as in multiple byte character encodings 
    like Unicode used in .Net where Char is one or more bytes (byte[n]). Also, the
    resulting translation from IEnumerable<byte> to IEnumerable<Char> can loose bytes
    or insert them (for example, "\n" vs. "\r\n") depending on the StreamReader instance
    CurrentEncoding.
    */
    
    0 讨论(0)
  • 2020-11-22 03:48

    You must not use StreamReader for binary files (like gifs or jpgs). StreamReader is for text data. You will almost certainly lose data if you use it for arbitrary binary data. (If you use Encoding.GetEncoding(28591) you will probably be okay, but what's the point?)

    Why do you need to use a StreamReader at all? Why not just keep the binary data as binary data and write it back to disk (or SQL) as binary data?

    EDIT: As this seems to be something people want to see... if you do just want to copy one stream to another (e.g. to a file) use something like this:

    /// <summary>
    /// Copies the contents of input to output. Doesn't close either stream.
    /// </summary>
    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);
        }    
    }
    

    To use it to dump a stream to a file, for example:

    using (Stream file = File.Create(filename))
    {
        CopyStream(input, file);
    }
    

    Note that Stream.CopyTo was introduced in .NET 4, serving basically the same purpose.

    0 讨论(0)
  • 2020-11-22 03:51
    public void CopyStream(Stream stream, string destPath)
    {
      using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write))
      {
        stream.CopyTo(fileStream);
      }
    }
    
    0 讨论(0)
  • 2020-11-22 03:53

    Here's an example that uses proper usings and implementation of idisposable:

    static void WriteToFile(string sourceFile, string destinationfile, bool append = true, int bufferSize = 4096)
    {
        using (var sourceFileStream = new FileStream(sourceFile, FileMode.OpenOrCreate))
        {
            using (var destinationFileStream = new FileStream(destinationfile, FileMode.OpenOrCreate))
            {
                while (sourceFileStream.Position < sourceFileStream.Length)
                {
                    destinationFileStream.WriteByte((byte)sourceFileStream.ReadByte());
                }
            }
        }
    }
    

    ...and there's also this

        public static void WriteToFile(FileStream stream, string destinationFile, int bufferSize = 4096, FileMode mode = FileMode.OpenOrCreate, FileAccess access = FileAccess.ReadWrite, FileShare share = FileShare.ReadWrite)
        {
            using (var destinationFileStream = new FileStream(destinationFile, mode, access, share))
            {
                while (stream.Position < stream.Length) 
                {
                    destinationFileStream.WriteByte((byte)stream.ReadByte());
                }
            }
        }
    

    The key is understanding the proper use of using (which should be implemented on the instantiation of the object that implements idisposable as shown above), and having a good idea as to how the properties work for streams. Position is literally the index within the stream (which starts at 0) that is followed as each byte is read using the readbyte method. In this case I am essentially using it in place of a for loop variable and simply letting it follow through all the way up to the length which is LITERALLY the end of the entire stream (in bytes). Ignore in bytes because it is practically the same and you will have something simple and elegant like this that resolves everything cleanly.

    Keep in mind, too, that the ReadByte method simply casts the byte to an int in the process and can simply be converted back.

    I'm gonna add another implementation I recently wrote to create a dynamic buffer of sorts to ensure sequential data writes to prevent massive overload

    private void StreamBuffer(Stream stream, int buffer)
    {
        using (var memoryStream = new MemoryStream())
        {
            stream.CopyTo(memoryStream);
            var memoryBuffer = memoryStream.GetBuffer();
    
            for (int i = 0; i < memoryBuffer.Length;)
            {
                var networkBuffer = new byte[buffer];
                for (int j = 0; j < networkBuffer.Length && i < memoryBuffer.Length; j++)
                {
                    networkBuffer[j] = memoryBuffer[i];
                    i++;
                }
                //Assuming destination file
                destinationFileStream.Write(networkBuffer, 0, networkBuffer.Length);
            }
        }
    }
    

    The explanation is fairly simple: we know that we need to keep in mind the entire set of data we wish to write and also that we only want to write certain amounts, so we want the first loop with the last parameter empty (same as while). Next, we initialize a byte array buffer that is set to the size of what's passed, and with the second loop we compare j to the size of the buffer and the size of the original one, and if it's greater than the size of the original byte array, end the run.

    0 讨论(0)
  • 2020-11-22 03:58

    As highlighted by Tilendor in Jon Skeet's answer, streams have a CopyTo method since .NET 4.

    var fileStream = File.Create("C:\\Path\\To\\File");
    myOtherObject.InputStream.Seek(0, SeekOrigin.Begin);
    myOtherObject.InputStream.CopyTo(fileStream);
    fileStream.Close();
    

    Or with the using syntax:

    using (var fileStream = File.Create("C:\\Path\\To\\File"))
    {
        myOtherObject.InputStream.Seek(0, SeekOrigin.Begin);
        myOtherObject.InputStream.CopyTo(fileStream);
    }
    
    0 讨论(0)
  • 2020-11-22 04:03

    Why not use a FileStream object?

    public void SaveStreamToFile(string fileFullPath, Stream stream)
    {
        if (stream.Length == 0) return;
    
        // Create a FileStream object to write a stream to a file
        using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length))
        {
            // Fill the bytes[] array with the stream data
            byte[] bytesInStream = new byte[stream.Length];
            stream.Read(bytesInStream, 0, (int)bytesInStream.Length);
    
            // Use FileStream object to write to the specified file
            fileStream.Write(bytesInStream, 0, bytesInStream.Length);
         }
    }
    
    0 讨论(0)
提交回复
热议问题