txt texto notas manejo lineas leer guardar escribir ejemplos datos crear bloc archivos archivo agregar c# .net stream

texto - leer y escribir archivos en c#



¿Cómo guardo una secuencia en un archivo en C#? (9)

¿Por qué no usar un objeto FileStream?

public void SaveStreamToFile(string fileFullPath, Stream stream) { if (stream.Length == 0) return; // Create a FileStream object to write a stream to a file using (FileStream fileStream = System.IO.File.Create(fileFullPath, (int)stream.Length)) { // Fill the bytes[] array with the stream data byte[] bytesInStream = new byte[stream.Length]; stream.Read(bytesInStream, 0, (int)bytesInStream.Length); // Use FileStream object to write to the specified file fileStream.Write(bytesInStream, 0, bytesInStream.Length); } }

Tengo un objeto StreamReader que inicialicé con una secuencia, ahora quiero guardar esta secuencia en el disco (la secuencia puede ser un .gif o .jpg o .pdf ).

Código existente:

StreamReader sr = new StreamReader(myOtherObject.InputStream);

  1. Necesito guardar esto en el disco (tengo el nombre del archivo).
  2. En el futuro es posible que desee almacenar esto en SQL Server.

También tengo el tipo de codificación, que necesitaré si lo guardo en SQL Server, ¿correcto?


Como lo destacó Tilendor en la respuesta de Jon Skeet, las transmisiones tienen un método CopyTo desde .NET 4.

var fileStream = File.Create("C://Path//To//File"); myOtherObject.InputStream.Seek(0, SeekOrigin.Begin); myOtherObject.InputStream.CopyTo(fileStream); fileStream.Close();

O con la sintaxis de using :

using (var fileStream = File.Create("C://Path//To//File")) { myOtherObject.InputStream.Seek(0, SeekOrigin.Begin); myOtherObject.InputStream.CopyTo(fileStream); }


No debes usar StreamReader para archivos binarios (como gifs o jpgs). StreamReader es para datos de texto . Es casi seguro que perderá datos si los utiliza para datos binarios arbitrarios. (Si usa Encoding.GetEncoding (28591) probablemente estará bien, pero ¿cuál es el punto?)

¿Por qué necesitas usar un StreamReader ? ¿Por qué no solo mantener los datos binarios como datos binarios y volver a escribirlos en el disco (o SQL) como datos binarios?

EDITAR: Como esto parece ser algo que la gente quiere ver ... si solo desea copiar una transmisión a otra (por ejemplo, a un archivo) use algo como esto:

/// <summary> /// Copies the contents of input to output. Doesn''t close either stream. /// </summary> public static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[8 * 1024]; int len; while ( (len = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, len); } }

Para usarlo para volcar un flujo a un archivo, por ejemplo:

using (Stream file = File.Create(filename)) { CopyStream(input, file); }

Tenga en cuenta que Stream.CopyTo se introdujo en .NET 4, sirviendo básicamente para el mismo propósito.


No obtengo todas las respuestas usando CopyTo , donde quizás los sistemas que usan la aplicación no se hayan actualizado a .NET 4.0+. Sé que a algunos les gustaría forzar a las personas a actualizar, pero la compatibilidad también es buena.

Otra cosa, en primer lugar, no uso una secuencia para copiar de otra secuencia. ¿Por qué no simplemente hacer:

byte[] bytes = myOtherObject.InputStream.ToArray();

Una vez que tenga los bytes, puede escribirlos fácilmente en un archivo:

public static void WriteFile(string fileName, byte[] bytes) { string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!path.EndsWith(@"/")) path += @"/"; if (File.Exists(Path.Combine(path, fileName))) File.Delete(Path.Combine(path, fileName)); using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write) { fs.Write(bytes, 0, (int)bytes.Length); fs.Close(); } }

Este código funciona como lo he probado con un archivo .jpg , aunque admito que solo lo he usado con archivos pequeños (menos de 1 MB). Una secuencia, sin copiar entre secuencias, sin necesidad de codificación, ¡simplemente escriba los bytes! ¡No es necesario que complique demasiado las cosas con StreamReader si ya tiene una transmisión que puede convertir a bytes directamente con .ToArray() !

Solo los posibles inconvenientes que puedo ver al hacerlo de esta manera es si tiene un archivo grande, tenerlo como una secuencia y usar .CopyTo() o equivalente permite a FileStream transmitirlo en lugar de usar una matriz de bytes y leer los bytes uno por uno. Podría ser más lento hacerlo de esta manera, como resultado. Pero no debería ahogarse ya que el método .Write() de FileStream maneja los bytes, y solo lo hace de un byte a la vez, por lo que no obstruirá la memoria, excepto que tendrá que tener suficiente memoria para mantenga la corriente como un objeto byte[] . En mi situación en la que usé esto, al obtener un OracleBlob , tuve que ir a un byte[] , era lo suficientemente pequeño y, además, no había transmisión disponible para mí, de todos modos, así que simplemente envié mis bytes a mi función, encima.

Otra opción, usando un flujo, sería usarlo con la función CopyStream Jon Skeet que estaba en otra publicación, esto solo usa FileStream para tomar el flujo de entrada y crear el archivo directamente. No usa File.Create , como hizo él (lo que inicialmente me pareció problemático, pero luego descubrió que probablemente solo era un error de VS ...).

/// <summary> /// Copies the contents of input to output. Doesn''t close either stream. /// </summary> public static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[8 * 1024]; int len; while ( (len = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, len); } } public static void WriteFile(string fileName, Stream inputStream) { string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); if (!path.EndsWith(@"/")) path += @"/"; if (File.Exists(Path.Combine(path, fileName))) File.Delete(Path.Combine(path, fileName)); using (FileStream fs = new FileStream(Path.Combine(path, fileName), FileMode.CreateNew, FileAccess.Write) { CopyStream(inputStream, fs); } inputStream.Close(); inputStream.Flush(); }


Otra opción es obtener el flujo a un byte[] y usar File.WriteAllBytes . Esto debería hacer:

using (var stream = new MemoryStream()) { input.CopyTo(stream); File.WriteAllBytes(file, stream.ToArray()); }

Envolverlo en un método de extensión le da un mejor nombre:

public void WriteTo(this Stream input, string file) { //your fav write method: using (var stream = File.Create(file)) { input.CopyTo(stream); } //or using (var stream = new MemoryStream()) { input.CopyTo(stream); File.WriteAllBytes(file, stream.ToArray()); } //whatever that fits. }


//If you don''t have .Net 4.0 :) public void SaveStreamToFile(Stream stream, string filename) { using(Stream destination = File.Create(filename)) Write(stream, destination); } //Typically I implement this Write method as a Stream extension method. //The framework handles buffering. public void Write(Stream from, Stream to) { for(int a = from.ReadByte(); a != -1; a = from.ReadByte()) to.WriteByte( (byte) a ); } /* Note, StreamReader is an IEnumerable<Char> while Stream is an IEnumbable<byte>. The distinction is significant such as in multiple byte character encodings like Unicode used in .Net where Char is one or more bytes (byte[n]). Also, the resulting translation from IEnumerable<byte> to IEnumerable<Char> can loose bytes or insert them (for example, "/n" vs. "/r/n") depending on the StreamReader instance CurrentEncoding. */


private void SaveFileStream(String path, Stream stream) { var fileStream = new FileStream(path, FileMode.Create, FileAccess.Write); stream.CopyTo(fileStream); fileStream.Dispose(); }


public void CopyStream(Stream stream, string destPath) { using (var fileStream = new FileStream(destPath, FileMode.Create, FileAccess.Write)) { stream.CopyTo(fileStream); } }


public void testdownload(stream input) { byte[] buffer = new byte[16345]; using (FileStream fs = new FileStream(this.FullLocalFilePath, FileMode.Create, FileAccess.Write, FileShare.None)) { int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { fs.Write(buffer, 0, read); } } }