Save and load MemoryStream to/from a file
Asked Answered
D

9

378

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?

Drypoint answered 24/12, 2011 at 10:55 Comment(2)
If you need to save to a file, why are you using a MemoryStream?Thielen
@Thielen What should I use? Can you give me an example?Drypoint
F
446

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);
Fadge answered 24/12, 2011 at 11:2 Comment(3)
memoryStream.CopyTo didn't seem to work for me, while WriteTo did. I think perhaps it was because my memoryStream.Position wasn't 0Eucken
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.Bullfrog
Adding [file|memory]Stream.Seek(0, SeekOrigin.Begin); before CopyTo will set the current position to 0, so that CopyTo will copy the complete stream.Wail
F
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);
Fetiparous answered 24/12, 2011 at 11:16 Comment(6)
Can I ask why you use FileMode.Create in the read sample vs FileMode.Open?Lepidolite
In the first code block, instead of manually copying memory stream to array, you can use built-in ms.ToArray() function.Mesothelium
It's important to set ms.Position = 0, otherwise byte array (and file) will contain all zeros.Dm
@Fernando68 the construct using (...){ } has the exactly the same effect.Bass
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.Sanford
@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.Fdic
G
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());
Grahamgrahame answered 7/2, 2013 at 9:59 Comment(0)
D
72
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()); 
Duthie answered 22/11, 2016 at 13:22 Comment(1)
Keep in mind this will re-allocate the whole buffer (MemoryStream.ToArray) byte[] copy = GC.AllocateUninitializedArray<byte>(count);Pussyfoot
R
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();
Ramillies answered 31/1, 2013 at 9:34 Comment(0)
M
19

For loading a file, I like this a lot better

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}
Mcniel answered 10/10, 2013 at 17:41 Comment(3)
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'Diaster
@Diaster 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.Demetra
@Diaster 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.Alroi
S
19

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;
}
Scrim answered 9/11, 2015 at 15:51 Comment(0)
B
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.

Bravissimo answered 6/10, 2016 at 2:17 Comment(0)
H
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);
Helwig answered 27/4, 2020 at 12:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.