Enregistrer et charger MemoryStream dans / à partir d'un fichier

281

Je sérialise une structure en un MemoryStreamet je souhaite enregistrer et charger la structure sérialisée.

Alors, comment enregistrer un MemoryStreamdans un fichier et le recharger à partir du fichier?

Mahdi Ghiasi
la source
Si vous devez enregistrer dans un fichier, pourquoi utilisez-vous un MemoryStream?
Oded
@Oded Que dois-je utiliser? Peux-tu me donner un exemple?
Mahdi Ghiasi

Réponses:

365

Vous pouvez utiliser des méthodes MemoryStream.WriteToou Stream.CopyTo(prises en charge dans la version 4.5.2, 4.5.1, 4.5, 4) pour écrire le contenu du flux de mémoire dans un autre flux.

memoryStream.WriteTo(fileStream);

Mettre à jour:

fileStream.CopyTo(memoryStream);
memoryStream.CopyTo(fileStream);
adatapost
la source
13
memoryStream.CopyTo ne semble pas fonctionner pour moi, contrairement à WriteTo. Je pense que c'était peut-être parce que mon memoryStream.Position n'était pas 0
Mark Adamson
10
Oui c'est correct. La différence entre eux est que CopyTo copie à partir de la position actuelle au lieu de toujours partir du début comme WriteTo le fait.
AnorZaken
6
L'ajout [file|memory]Stream.Seek(0, SeekOrigin.Begin);avant CopyTodéfinira la position actuelle à 0, ce qui CopyTocopiera le flux complet.
Martin Backasch
264

En supposant que le nom MemoryStream est ms.

Ce code écrit MemoryStream dans un fichier:

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

et cela lit un fichier dans un 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);
}

Dans .Net Framework 4+, vous pouvez simplement copier FileStream vers MemoryStream et inverser aussi simple que ceci:

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

Et l'inverse (MemoryStream à FileStream):

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write))
    ms.CopyTo(file);
Ashkan Mobayen Khiabani
la source
1
Puis-je vous demander pourquoi vous utilisez FileMode.Create dans l'exemple de lecture vs FileMode.Open?
Philter
6
Dans le premier bloc de code, au lieu de copier manuellement le flux de mémoire dans le tableau, vous pouvez utiliser la ms.ToArray()fonction intégrée.
Gman
5
Il est important de définir ms.Position = 0, sinon le tableau d'octets (et le fichier) contiendra tous les zéros.
Gregory Khrapunovich
1
@ Fernando68 la construction using (...){ }a exactement le même effet.
Fabricio Araujo
2
Tout comme un avertissement pour les autres `` utilisant (FileStream '' et `` ms.CopyTo (fichier) '' définit la position à la fin du fichier et vous devez réinitialiser le flux de mémoire par la suite.
Rebecca
64

Le flux devrait vraiment être éliminé même s'il y a une exception (très probablement sur les E / S de fichier) - l'utilisation de clauses est mon approche préférée pour cela, donc pour écrire votre MemoryStream, vous pouvez utiliser:

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

Et pour le relire:

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

Si les fichiers sont volumineux, il convient de noter que l'opération de lecture utilisera deux fois plus de mémoire que la taille totale du fichier . Une solution à cela consiste à créer le MemoryStream à partir du tableau d'octets - le code suivant suppose que vous n'écrirez pas alors sur ce flux.

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

Ma recherche (ci-dessous) montre que le tampon interne est le même tableau d'octets que vous le passez, il devrait donc économiser de la mémoire.

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

Pour ceux qui recherchent les versions courtes:

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

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

La réponse combinée pour écrire dans un fichier peut être;

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

Enregistrer dans un fichier

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

Charger depuis un fichier

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

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

À l'origine, l'implémentation de cette classe a été publiée ici

et

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

Pour charger un fichier, j'aime beaucoup mieux cela

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}
ProVega
la source
Si le fichier est ouvert dans Microsoft Word - existe-t-il un moyen de créer un flux de mémoire à partir de ce fichier? Je reçois une erreur «le fichier est ouvert par un autre processus»
FrenkyB
@FrenkyB Je rencontre aussi beaucoup ça. Si vous avez ouvert le fichier dans Word ou dans une autre application, vous ne pouvez pas le faire. Fermez simplement le fichier dans Word.
Kristopher
@FrenkyB Pouvez-vous faire un File.Copy? J'ai trouvé que cela fonctionne, puis lisez ce fichier dans un flux et supprimez le nouveau fichier ... horrible, mais semble fonctionner.
ridecar2
3

J'utilise un panneau de commande pour ajouter une image ou même flux vidéo, mais vous pouvez enregistrer l'image sur SQL Server comme image ou MySQL comme largeblob . Ce code fonctionne beaucoup pour moi. Vérifiez-le.

Ici, vous enregistrez l'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();

Et ici, vous pouvez charger, mais j'ai utilisé un contrôle PictureBox.

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

L'espoir aide.

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

        }
    }
}

Utilisation: -

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