Guardar y cargar MemoryStream a / desde un archivo


281

Estoy serializando una estructura en MemoryStreamay quiero guardar y cargar la estructura serializada.

Entonces, ¿cómo guardar un MemoryStreamarchivo en un archivo y también cargarlo desde el archivo?


Si necesita guardar en un archivo, ¿por qué está utilizando un MemoryStream?
Oded

@Oded ¿Qué debo usar? ¿Puedes darme un ejemplo?
Mahdi Ghiasi

Respuestas:


365

Puede usar métodos ( MemoryStream.WriteToo Stream.CopyTocompatibles con la versión 4.5.2, 4.5.1, 4.5, 4) para escribir el contenido de la secuencia de memoria en otra secuencia.

memoryStream.WriteTo(fileStream);

Actualizar:

fileStream.CopyTo(memoryStream);
memoryStream.CopyTo(fileStream);

13
memoryStream.CopyTo no parecía funcionar para mí, mientras que WriteTo sí. Creo que tal vez fue porque mi memoria Stream.Position no era 0
Mark Adamson

10
Si, eso es correcto. La diferencia entre ellos es que CopyTo copia desde cualquier posición actual en lugar de siempre desde el principio como lo hace WriteTo.
AnorZaken

66
Agregar [file|memory]Stream.Seek(0, SeekOrigin.Begin);antes CopyToestablecerá la posición actual en 0, por lo que CopyTocopiará la secuencia completa.
Martin Backasch

264

Suponiendo que el nombre MemoryStream es ms.

Este código escribe MemoryStream en un archivo:

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

y esto lee un archivo en 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);
}

En .Net Framework 4+, simplemente puede copiar FileStream a MemoryStream y revertirlo de la siguiente manera:

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

Y el reverso (MemoryStream a FileStream):

using (FileStream file = new FileStream("file.bin", FileMode.Create, System.IO.FileAccess.Write))
    ms.CopyTo(file);

1
¿Puedo preguntar por qué usas FileMode.Create en la muestra de lectura vs FileMode.Open?
Philter

66
En el primer bloque de código, en lugar de copiar manualmente el flujo de memoria a la matriz, puede usar la ms.ToArray()función incorporada.
Gman

55
Es importante establecer ms.Position = 0; de lo contrario, la matriz de bytes (y el archivo) contendrán todos los ceros.
Gregory Khrapunovich

1
@ Fernando68 la construcción using (...){ }tiene exactamente el mismo efecto.
Fabricio Araujo

2
Solo como una advertencia a los demás 'usando (FileStream' y 'ms.CopyTo (file)' establece la posición al final del archivo y luego debe restablecer el flujo de memoria.
Rebecca

64

La transmisión realmente debería eliminarse incluso si hay una excepción (muy probablemente en E / S de archivo): el uso de cláusulas es mi enfoque favorito para esto, por lo que para escribir su MemoryStream, puede usar:

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

Y para leerlo de nuevo:

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 los archivos son grandes, vale la pena señalar que la operación de lectura usará el doble de memoria que el tamaño total del archivo . Una solución para eso es crear MemoryStream a partir de la matriz de bytes: el siguiente código supone que no escribirás en esa secuencia.

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

Mi investigación (a continuación) muestra que el búfer interno es el mismo conjunto de bytes que lo pasa, por lo que debería ahorrar memoria.

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

41

Para cualquiera que busque las versiones cortas:

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

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

20

La respuesta combinada para escribir en un archivo puede ser;

MemoryStream ms = new MemoryStream();    
FileStream file = new FileStream("file.bin", FileMode.Create, FileAccess.Write);
ms.WriteTo(file);
file.Close();
ms.Close();

15

Guardar en un archivo

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

Cargar desde un archivo

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

dónde

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

Originalmente, la implementación de esta clase se publicó aquí

y

[Serializable]
public class Car
{
    public string Name;
}

14

Para cargar un archivo, me gusta mucho más

MemoryStream ms = new MemoryStream();
using (FileStream fs = File.OpenRead(file))
{
    fs.CopyTo(ms);
}

Si el archivo se abre en Microsoft Word, ¿hay alguna forma de crear una secuencia de memoria a partir de ese archivo? Recibo un error 'el archivo se abre por otro proceso'
FrenkyB

@FrenkyB También me encuentro con esto mucho. Si tiene el archivo abierto en Word o en alguna otra aplicación, no podrá hacerlo. Simplemente cierre el archivo en Word.
Kristopher

@FrenkyB ¿Puedes hacer un File.Copy? He encontrado que funciona, luego leí ese archivo en una secuencia y eliminé el nuevo archivo ... horrible, pero parece funcionar.
ridecar2

3

Utilizo un Control de panel para agregar una imagen o incluso transmitir video, pero puede guardar la imagen en SQL Server como Imagen o MySQL como bloque grande . Este código me funciona mucho. Echale un vistazo.

Aquí guardas la imagen

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

Y aquí puedes cargar, pero utilicé un PictureBox Control.

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

La esperanza ayuda.


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

        }
    }
}

Uso: -

ImageWaterMarkBuilder.AddStream(stream).AddWaterMark("").CompileAndSave(filePath);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.