2011-12-24 24 views
182

Estoy serializando una estructura en un MemoryStream y quiero guardar y cargar la estructura serializada.Guarde y cargue MemoryStream a/desde un archivo

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

+0

Si necesita guardar en un archivo, ¿por qué estás usando un 'MemoryStream'? – Oded

+0

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

Respuesta

269

Puede usar los métodos MemoryStream.WriteTo o Stream.CopyTo (admitidos en el marco de trabajo versión 4.5.2, 4.5.1, 4.5, 4) para escribir el contenido de la secuencia de la memoria en otra secuencia.

memoryStream.WriteTo(fileStream); 

Actualización:

fileStream.CopyTo(memoryStream); 
memoryStream.CopyTo(fileStream); 
+8

memoryStream.CopyTo no parece funcionar para mí, mientras que WriteTo lo hizo. Creo que fue porque mi memoryStream.Position no era 0 –

+6

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

+0

Agregar ['[archivo | memoria] Stream.Seek (0, SeekOrigin.Begin);'] (https://msdn.microsoft.com/en-us/library/system.io.stream.seek (v = vs .110) .aspx) antes de que 'CopyTo' establezca la posición actual en 0, de modo que 'CopyTo' copiará la secuencia completa. –

184

Suponiendo que el nombre MemoryStream es ms.

Este código escribe MemoryStream a 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 se lee un archivo a 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+, puede simplemente copiar FileStream a MemoryStream y revertir tan simple como esto:

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

y de marcha atrás (MemoryStream a FileStream):

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

¿Puedo preguntar por qué utiliza FileMode.Create en la muestra de lectura frente a FileMode.Open? – Philter

+4

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

+4

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

17

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

La corriente debe realmente por dispuesta incluso si hay una excepción (muy probablemente en el archivo de E/S) - el uso de cláusulas son mi método favorito para esto, así que para escribir su MemoryStream, puede utilizar:

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

y para leer 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, entonces vale la pena señalar que la operación de lectura utilizará el doble de memoria como t El tamaño total del archivo. Una solución para eso es crear el MemoryStream desde la matriz de bytes; el siguiente código asume que no escribirá 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 a medida 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()); 
+0

mejor respuesta aquí –

13

Para cargar un archivo, me gusta esto mucho mejor

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

Si el archivo se abre en Microsoft Word, ¿hay alguna manera de crear una secuencia de memoria desde ese archivo? Estoy recibiendo un error 'archivo se abre por otro proceso' – FrenkyB

+0

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

10

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

carga de un archivo de

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

donde

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 ha sido publicado here

y

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

utilizo un panel de control para agregar una imagen o incluso flujo de vídeo, pero puede guardar la imagen en SQL Server como Imagen o MySQL como largeblob. Este código funciona para mí mucho. Echale un vistazo.

Aquí se guarda 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í se puede cargar, pero utilizó un control PictureBox.

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

Hope helps.

16

Para el que busque las versiones cortas:

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

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