374

I am serializing an structure into a MemoryStream and I want to save and load the serialized structure.

So, How to Save a MemoryStream into a file and also load it back from file?

Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
Mahdi Ghiasi
  • 14,873
  • 19
  • 71
  • 119

9 Answers9

442

You may use MemoryStream.WriteTo or Stream.CopyTo (supported in framework version 4.5.2, 4.5.1, 4.5, 4) methods to write content of memory stream to another stream.

memoryStream.WriteTo(fileStream);

Update:

fileStream.CopyTo(memoryStream);
memoryStream.CopyTo(fileStream);
KV Prajapati
  • 93,659
  • 19
  • 148
  • 186
  • 19
    memoryStream.CopyTo didn't seem to work for me, while WriteTo did. I think perhaps it was because my memoryStream.Position wasn't 0 – Mark Adamson Jul 09 '14 at 14:16
  • 20
    Yes that is correct. The difference between them is that CopyTo copies from whatever the current position is instead of always from the begining like WriteTo does. – AnorZaken Sep 14 '15 at 19:33
  • 13
    Adding [`[file|memory]Stream.Seek(0, SeekOrigin.Begin);`](https://msdn.microsoft.com/en-us/library/system.io.stream.seek(v=vs.110).aspx) before `CopyTo` will set the current position to 0, so that `CopyTo` will copy the complete stream. – Martin Backasch Nov 14 '17 at 14:37
329

Assuming that MemoryStream name is ms.

This code writes down MemoryStream to a file:

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write)) {
   byte[] bytes = new byte[ms.Length];
   ms.Read(bytes, 0, (int)ms.Length);
   file.Write(bytes, 0, bytes.Length);
   ms.Close();
}

and this reads a file to a MemoryStream :

using (MemoryStream ms = new MemoryStream())
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
   byte[] bytes = new byte[file.Length];
   file.Read(bytes, 0, (int)file.Length);
   ms.Write(bytes, 0, (int)file.Length);
}

In .Net Framework 4+, You can simply copy FileStream to MemoryStream and reverse as simple as this:

MemoryStream ms = new MemoryStream();
using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read))
    file.CopyTo(ms);

And the Reverse (MemoryStream to FileStream):

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write))
    ms.CopyTo(file);
Ashkan Mobayen Khiabani
  • 33,575
  • 33
  • 102
  • 171
  • 1
    Can I ask why you use FileMode.Create in the read sample vs FileMode.Open? – Philter Feb 14 '13 at 17:58
  • 7
    In the first code block, instead of manually copying memory stream to array, you can use built-in `ms.ToArray()` function. – Gman Mar 25 '13 at 12:36
  • 10
    It's important to set ms.Position = 0, otherwise byte array (and file) will contain all zeros. – Gregory Khrapunovich Nov 04 '13 at 21:01
  • 1
    @Fernando68 the construct `using (...){ }` has the exactly the same effect. – Fabricio Araujo May 03 '17 at 20:59
  • 3
    Just as a warning to others 'using (FileStream' and 'ms.CopyTo(file)' sets the position tothe end of the file and you need to reset the memorystream afterwards. – Rebecca Nov 02 '18 at 11:21
  • @GregoryKhrapunovich , Its like a cassete tape, while we create it... we write to the very end. Now the tape has to be rewound before we put it in the walkman. – Paras Parmar Feb 02 '21 at 16:52
78

The stream should really by disposed of even if there's an exception (quite likely on file I/O) - using clauses are my favourite approach for this, so for writing your MemoryStream, you can use:

using (FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write)) {
    memoryStream.WriteTo(file);
}

And for reading it back:

using (FileStream file = new FileStream("file.bin", FileMode.Open, FileAccess.Read)) {
    byte[] bytes = new byte[file.Length];
    file.Read(bytes, 0, (int)file.Length);
    ms.Write(bytes, 0, (int)file.Length);
}

If the files are large, then it's worth noting that the reading operation will use twice as much memory as the total file size. One solution to that is to create the MemoryStream from the byte array - the following code assumes you won't then write to that stream.

MemoryStream ms = new MemoryStream(bytes, writable: false);

My research (below) shows that the internal buffer is the same byte array as you pass it, so it should save memory.

byte[] testData = new byte[] { 104, 105, 121, 97 };
var ms = new MemoryStream(testData, 0, 4, false, true);
Assert.AreSame(testData, ms.GetBuffer());
Rob Church
  • 6,783
  • 3
  • 41
  • 46
68
var memoryStream = new MemoryStream(File.ReadAllBytes("1.dat"));

File.WriteAllBytes("1.dat", memoryStream.ToArray()); 

.GetBuffer can be used in some cases to get the internal buffer instead of allocating second array :

byte[] bytes = File.ReadAllBytes("1.dat");
var memoryStream = new MemoryStream(bytes, 0, bytes.Length, true, true); 

File.WriteAllBytes("1.dat", memoryStream.GetBuffer()); 
Slai
  • 22,144
  • 5
  • 45
  • 53
  • 2
    Keep in mind this will re-allocate the whole buffer (MemoryStream.ToArray) `byte[] copy = GC.AllocateUninitializedArray(count);` – CorrM Apr 07 '22 at 04:21
24

The combined answer for writing to a file can be;

MemoryStream ms = new MemoryStream();    
FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write);
ms.WriteTo(file);
file.Close();
ms.Close();
Berkay Turancı
  • 3,373
  • 4
  • 32
  • 45
19

For loading a file, I like this a lot better

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}
ProVega
  • 5,864
  • 2
  • 36
  • 34
  • If file is opened in Microsoft Word - is there a way for creating a memory stream from that file? I am receiving an error 'file is opened by another process' – FrenkyB Dec 21 '13 at 06:17
  • @FrenkyB I also run into this a lot. If you have the file open in Word or some other app then you can't get do it. Just close the file in Word. – Kristopher Nov 10 '15 at 18:50
  • @FrenkyB Can you do a File.Copy? I have found that to work, then read from that file into a stream and delete the new file... horrible, but seems to work. – ridecar2 Jul 09 '19 at 14:56
18

Save into a file

Car car = new Car();
car.Name = "Some fancy car";
MemoryStream stream = Serializer.SerializeToStream(car);
System.IO.File.WriteAllBytes(fileName, stream.ToArray());

Load from a file

using (var stream = new MemoryStream(System.IO.File.ReadAllBytes(fileName)))
{
    Car car = (Car)Serializer.DeserializeFromStream(stream);
}

where

using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Serialization
{
    public class Serializer
    {
        public static MemoryStream SerializeToStream(object o)
        {
            MemoryStream stream = new MemoryStream();
            IFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, o);
            return stream;
        }

        public static object DeserializeFromStream(MemoryStream stream)
        {
            IFormatter formatter = new BinaryFormatter();
            stream.Seek(0, SeekOrigin.Begin);
            object o = formatter.Deserialize(stream);
            return o;
        }
    }
}

Originally the implementation of this class has been posted here

and

[Serializable]
public class Car
{
    public string Name;
}
Community
  • 1
  • 1
Vadim Gremyachev
  • 57,952
  • 20
  • 129
  • 193
4

I use a Panel Control to add a image or even stream video, but you can save the image on SQL Server as Image or MySQL as largeblob. This code works for me a lot. Check it out.

Here you save the image

MemoryStream ms = new MemoryStream();
Bitmap bmp = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(bmp, panel1.Bounds);
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); // here you can change the Image format
byte[] Pic_arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(Pic_arr, 0, Pic_arr.Length);
ms.Close();

And here you can load, but I used a PictureBox Control.

MemoryStream ms = new MemoryStream(picarr);
ms.Seek(0, SeekOrigin.Begin);
fotos.pictureBox1.Image = System.Drawing.Image.FromStream(ms);

Hope helps.

Leinad
  • 111
  • 10
3
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;

namespace ImageWriterUtil
{
    public class ImageWaterMarkBuilder
    {
        //private ImageWaterMarkBuilder()
        //{
        //}
        Stream imageStream;
        string watermarkText = "©8Bytes.Technology";
        Font font = new System.Drawing.Font("Brush Script MT", 30, FontStyle.Bold, GraphicsUnit.Pixel);
        Brush brush = new SolidBrush(Color.Black);
        Point position;
        public ImageWaterMarkBuilder AddStream(Stream imageStream)
        {
            this.imageStream = imageStream;
            return this;
        }
        public ImageWaterMarkBuilder AddWaterMark(string watermarkText)
        {
            this.watermarkText = watermarkText;
            return this;
        }
        public ImageWaterMarkBuilder AddFont(Font font)
        {
            this.font = font;
            return this;
        }

        public ImageWaterMarkBuilder AddFontColour(Color color)
        {
            this.brush = new SolidBrush(color);
            return this;
        }
        public ImageWaterMarkBuilder AddPosition(Point position)
        {
            this.position = position;
            return this;
        }

        public void CompileAndSave(string filePath)
        {

            //Read the File into a Bitmap.
            using (Bitmap bmp = new Bitmap(this.imageStream, false))
            {
                using (Graphics grp = Graphics.FromImage(bmp))
                {


                    //Determine the size of the Watermark text.
                    SizeF textSize = new SizeF();
                    textSize = grp.MeasureString(watermarkText, font);

                    //Position the text and draw it on the image.
                    if (position == null)
                        position = new Point((bmp.Width - ((int)textSize.Width + 10)), (bmp.Height - ((int)textSize.Height + 10)));
                    grp.DrawString(watermarkText, font, brush, position);

                    using (MemoryStream memoryStream = new MemoryStream())
                    {
                        //Save the Watermarked image to the MemoryStream.
                        bmp.Save(memoryStream, ImageFormat.Png);
                        memoryStream.Position = 0;
                       // string fileName = Path.GetFileNameWithoutExtension(filePath);
                        // outPuthFilePath = Path.Combine(Path.GetDirectoryName(filePath), fileName + "_outputh.png");
                        using (FileStream file = new FileStream(filePath, FileMode.Create, System.IO.FileAccess.Write))
                        {
                            byte[] bytes = new byte[memoryStream.Length];
                            memoryStream.Read(bytes, 0, (int)memoryStream.Length);
                            file.Write(bytes, 0, bytes.Length);
                            memoryStream.Close();
                        }
                    }
                }
            }

        }
    }
}

Usage :-

ImageWaterMarkBuilder.AddStream(stream).AddWaterMark("").CompileAndSave(filePath);