Speichern und laden Sie MemoryStream in / aus einer Datei

281

Ich serialisiere eine Struktur in eine MemoryStream und möchte die serialisierte Struktur speichern und laden.

Also, wie man ein MemoryStreamin eine Datei speichert und es auch wieder aus der Datei lädt?

Mahdi Ghiasi
quelle
Wenn Sie in einer Datei speichern müssen, warum verwenden Sie eine MemoryStream?
Oded
@Oded Was soll ich verwenden? Kannst du mir ein Beispiel geben?
Mahdi Ghiasi

Antworten:

365

Sie können MemoryStream.WriteTooder Stream.CopyTo(in Framework-Version 4.5.2, 4.5.1, 4.5, 4 unterstützt) Methoden verwenden, um Inhalte des Speicherstroms in einen anderen Stream zu schreiben.

memoryStream.WriteTo(fileStream);

Aktualisieren:

fileStream.CopyTo(memoryStream);
memoryStream.CopyTo(fileStream);
Adatapost
quelle
13
memoryStream.CopyTo schien bei mir nicht zu funktionieren, während WriteTo es tat. Ich denke, vielleicht lag es daran, dass mein memoryStream.Position nicht 0 war
Mark Adamson
10
Ja, das ist richtig. Der Unterschied zwischen ihnen besteht darin, dass CopyTo von jeder aktuellen Position kopiert wird, anstatt immer von Anfang an wie WriteTo.
AnorZaken
6
Hinzufügen [file|memory]Stream.Seek(0, SeekOrigin.Begin);bevor CopyTodie aktuelle Position auf 0 gesetzt, so dass CopyToder kompletten Strom kopieren.
Martin Backasch
263

Angenommen, der Name MemoryStream lautet ms .

Dieser Code schreibt MemoryStream in eine Datei:

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();
}

und dies liest eine Datei in einen 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+ können Sie FileStream einfach in MemoryStream kopieren und so einfach umkehren:

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

Und die Umkehrung (MemoryStream zu FileStream):

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write))
    ms.CopyTo(file);
Ashkan Mobayen Khiabani
quelle
1
Kann ich fragen, warum Sie FileMode.Create im Lesebeispiel gegen FileMode.Open verwenden?
Philter
6
Anstatt den Speicherstrom manuell in ein Array zu kopieren, können Sie im ersten Codeblock die integrierte ms.ToArray()Funktion verwenden.
Gman
5
Es ist wichtig, ms.Position = 0 zu setzen, da sonst das Byte-Array (und die Datei) alle Nullen enthalten.
Gregory Khrapunovich
1
@ Fernando68 das Konstrukt using (...){ }hat genau den gleichen Effekt.
Fabricio Araujo
2
Nur als Warnung an andere, die (FileStream 'und' ms.CopyTo (file) 'verwenden, wird die Position am Ende der Datei festgelegt, und Sie müssen den Memorystream anschließend zurücksetzen
Rebecca,
63

Der Stream sollte wirklich entsorgt werden, auch wenn es eine Ausnahme gibt (sehr wahrscheinlich bei Datei-E / A). Die Verwendung von Klauseln ist mein bevorzugter Ansatz, sodass Sie zum Schreiben Ihres MemoryStream Folgendes verwenden können:

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

Und zum Zurücklesen:

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);
}

Wenn die Dateien groß sind, ist zu beachten, dass der Lesevorgang doppelt so viel Speicher benötigt wie die gesamte Dateigröße . Eine Lösung hierfür besteht darin, den MemoryStream aus dem Byte-Array zu erstellen. Im folgenden Code wird davon ausgegangen, dass Sie dann nicht in diesen Stream schreiben.

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

Meine Forschung (unten) zeigt, dass der interne Puffer das gleiche Byte-Array ist, mit dem Sie ihn übergeben, sodass Speicherplatz gespart werden sollte.

byte[] testData = new byte[] { 104, 105, 121, 97 };
var ms = new MemoryStream(testData, 0, 4, false, true);
Assert.AreSame(testData, ms.GetBuffer());
Rob Church
quelle
41

Für alle, die nach Kurzversionen suchen:

var memoryStream = new MemoryStream(File.ReadAllBytes("1.dat"));

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

Die kombinierte Antwort zum Schreiben in eine Datei kann sein;

MemoryStream ms = new MemoryStream();    
FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write);
ms.WriteTo(file);
file.Close();
ms.Close();
Berkay Turancı
quelle
15

In einer Datei speichern

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

Laden aus einer Datei

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

wo

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;
        }
    }
}

Ursprünglich wurde die Implementierung dieser Klasse hier veröffentlicht

und

[Serializable]
public class Car
{
    public string Name;
}
Vadim Gremyachev
quelle
14

Zum Laden einer Datei gefällt mir das viel besser

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}
ProVega
quelle
Wenn eine Datei in Microsoft Word geöffnet wird - gibt es eine Möglichkeit, aus dieser Datei einen Speicherstrom zu erstellen? Ich
erhalte die
@FrenkyB Ich stoße auch oft darauf. Wenn Sie die Datei in Word oder einer anderen App geöffnet haben, können Sie dies nicht tun. Schließen Sie einfach die Datei in Word.
Kristopher
@FrenkyB Kannst du eine File.Copy machen? Ich habe festgestellt, dass das funktioniert, dann aus dieser Datei in einen Stream gelesen und die neue Datei gelöscht ... schrecklich, scheint aber zu funktionieren.
Ridecar2
3

Ich verwende ein Bedienfeld, um ein Bild hinzuzufügen oder sogar Videos zu streamen, aber Sie können das Bild auf SQL Server als Image oder MySQL als Largeblob speichern . Dieser Code funktioniert bei mir sehr. Hör zu.

Hier speichern Sie das Bild

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();

Und hier können Sie laden, aber ich habe ein PictureBox-Steuerelement verwendet.

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

Hoffnung hilft.

Leinad
quelle
1
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();
                        }
                    }
                }
            }

        }
    }
}

Verwendung :-

ImageWaterMarkBuilder.AddStream(stream).AddWaterMark("").CompileAndSave(filePath);
Ragesh Punathil
quelle