¿Cuál es la mejor manera de copiar el contenido de una secuencia a otra? ¿Hay un método de utilidad estándar para esto?¿Cómo copio el contenido de una secuencia a otra?
Respuesta
De .NET 4.5 en adelante, no es el Stream.CopyToAsync
method
input.CopyToAsync(output);
Esto devolverá un Task
en que puede mantenerse en cuando esté terminado, así:
await input.CopyToAsync(output)
// Code from here on will be run in a continuation.
Tenga en cuenta que dependiendo de donde se realiza la llamada al CopyToAsync
, el código que sigue puede continuar o no en el mismo hilo que lo llamó.
El SynchronizationContext
que se capturó al llamar al await
determinará en qué subproceso se ejecutará la continuación.
Además, esta llamada (y este es un detalle de implementación sujeto a cambios) todavía lee y escribe secuencias (simplemente no pierde un bloqueo de hilos en la finalización de E/S).
De .NET 4.0 en adelante, no es es el Stream.CopyTo
method
input.CopyTo(output);
para .NET 3.5 y antes de
No hay nada al horno en el marco para ayudar con esto; tiene que copiar el contenido manualmente, así:
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write (buffer, 0, read);
}
}
Tenga en cuenta que esta no es la forma más rápida de hacerlo. En el fragmento de código proporcionado, debe esperar a que se complete la escritura antes de que se lea un nuevo bloque. Al hacer la lectura y la escritura de forma asíncrona, esta espera desaparecerá. En alguna situación, esto hará que la copia sea dos veces más rápida. Sin embargo, hará que el código sea mucho más complicado, por lo que si la velocidad no es un problema, manténgala simple y use este simple bucle. Esta pregunta en StackOverflow tiene algún código que ilustra la lectura/escritura asíncrona: http: // stackoverflow.com/questions/1540658/net-asynchronous-stream-read-write Saludos, Sebastiaan –
¿32.768 es el tamaño de byte recomendado? He visto cantidades menores antes, como 4,096. – Josh
@Josh 32.768 es una copia con fragmentos de 32 KB. 4096 usa 4 pedazos de KB. Será un poco más lento pero usará menos memoria. – Nick
Lamentablemente, no hay una solución realmente simple. Usted puede intentar algo así:
Stream s1, s2;
byte[] buffer = new byte[4096];
int bytesRead = 0;
while (bytesRead = s1.Read(buffer, 0, buffer.Length) > 0) s2.Write(buffer, 0, bytesRead);
s1.Close(); s2.Close();
Pero el problema con esto tan diferente implementación de la clase Stream podría comportarse de manera diferente si no hay nada que leer. Una secuencia que lea un archivo de un disco duro local probablemente bloqueará hasta que la operación de lectura haya leído suficientes datos del disco para llenar el búfer y solo devolverá menos datos si llega al final del archivo. Por otro lado, una lectura de flujo de la red puede devolver menos datos aunque haya más datos por recibir.
Siempre verifique la documentación de la clase de flujo específico que está utilizando antes de usar una solución genérica.
La solución genérica funcionará aquí; la respuesta de Nick es buena. El tamaño del búfer es una elección arbitraria, por supuesto, pero 32K suena razonable. Creo que la solución de Nick es correcta para no cerrar las transmisiones, dejen eso al propietario. –
Las preguntas básicas que diferencian a las implementaciones de "CopyStream" son:
- tamaño del búfer de lectura
- tamaño de las escrituras
- Se puede utilizar más de un hilo (escritura mientras estamos leyendo)
Las respuestas a estas preguntas dan como resultado implementaciones muy diferentes de CopyStream y dependen del tipo de transmisión que tenga y de lo que intente optimizar. La "mejor" implementación incluso necesitaría saber qué hardware específico estaban leyendo y escribiendo las secuencias.
... o la mejor implementación podría tener sobrecargas para permitirle especificar el tamaño del búfer, el tamaño de escritura y si se permiten los subprocesos? – MarkJ
Puede haber una manera de hacer esto de manera más eficiente, dependiendo del tipo de flujo con el que esté trabajando. Si puede convertir una o ambas secuencias en un MemoryStream, puede usar el método GetBuffer para trabajar directamente con una matriz de bytes que represente sus datos. Esto le permite usar métodos como Array.CopyTo, que resumen todos los problemas planteados por fryguybob. Simplemente puede confiar en .NET para conocer la forma óptima de copiar los datos.
si quieres un procdure para copiar una corriente a otra la que Nick ha escrito está bien, pero le falta el restablecimiento posición, debería ser
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[32768];
long TempPos = input.Position;
while (true)
{
int read = input.Read (buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write (buffer, 0, read);
}
input.Position = TempPos;// or you make Position = 0 to set it at the start
}
pero no si está en tiempo de ejecución mediante un procedimiento usted usa corriente de memoria
Stream output = new MemoryStream();
byte[] buffer = new byte[32768]; // or you specify the size you want of your buffer
long TempPos = input.Position;
while (true)
{
int read = input.Read (buffer, 0, buffer.Length);
if (read <= 0)
return;
output.Write (buffer, 0, read);
}
input.Position = TempPos;// or you make Position = 0 to set it at the start
No debe cambiar la posición de la secuencia de entrada, porque no todas las secuencias permiten el acceso aleatorio. En una transmisión de red, por ejemplo, no puede cambiar de posición, solo leer y/o escribir. –
En realidad, hay una manera menos torpe de hacer una copia de secuencia. Sin embargo, tenga en cuenta que esto implica que puede almacenar todo el archivo en la memoria. No intente usar esto si está trabajando con archivos que abarcan cientos de megabytes o más, sin precaución.
public static void CopyStream(Stream input, Stream output)
{
using (StreamReader reader = new StreamReader(input))
using (StreamWriter writer = new StreamWriter(output))
{
writer.Write(reader.ReadToEnd());
}
}
NOTA: También puede haber algunas cuestiones relativas a la codificación de datos y caracteres binarios.
El constructor predeterminado para StreamWriter crea una secuencia UTF8 sin una lista de materiales (http://msdn.microsoft.com/en-us/library/fysy0a4b.aspx) por lo que no hay peligro de problemas de codificación. Es casi seguro que los datos binarios no deberían copiarse de esta manera. –
se podría argumentar fácilmente que cargar "el archivo completo en la memoria" no se considera "menos severo". – Seph
obtengo excepción de memoria debido a esto – ColacX
Utilizo los siguientes métodos de extensión. Han optimizado las sobrecargas para cuando una secuencia es un MemoryStream.
public static void CopyTo(this Stream src, Stream dest)
{
int size = (src.CanSeek) ? Math.Min((int)(src.Length - src.Position), 0x2000) : 0x2000;
byte[] buffer = new byte[size];
int n;
do
{
n = src.Read(buffer, 0, buffer.Length);
dest.Write(buffer, 0, n);
} while (n != 0);
}
public static void CopyTo(this MemoryStream src, Stream dest)
{
dest.Write(src.GetBuffer(), (int)src.Position, (int)(src.Length - src.Position));
}
public static void CopyTo(this Stream src, MemoryStream dest)
{
if (src.CanSeek)
{
int pos = (int)dest.Position;
int length = (int)(src.Length - src.Position) + pos;
dest.SetLength(length);
while(pos < length)
pos += src.Read(dest.GetBuffer(), pos, length - pos);
}
else
src.CopyTo((Stream)dest);
}
MemoryStream tiene .WriteTo (outstream);
y .NET 4.0 tiene .CopyTo en el objeto de transmisión normal.
.NET 4.0:
instream.CopyTo(outstream);
No veo muchas muestras en la web usando estos métodos. ¿Esto es porque son bastante nuevos o hay algunas limitaciones? – GeneS
Es porque son nuevos en .NET 4.0. Stream.CopyTo() básicamente hace exactamente lo mismo para el bucle que la respuesta aprobada, con algunos controles de cordura adicionales. El tamaño del búfer predeterminado es 4096, pero también hay una sobrecarga para especificar uno más grande. –
La secuencia debe rebobinarse después de la copia: instream.Position = 0; – Draykos
Dado que ninguna de las respuestas han cubierto de forma asíncrona de la copia de una secuencia a otra, aquí es un patrón que he utilizado con éxito en una aplicación de reenvío de puertos para copiar datos de un flujo de red a otro. Carece de manejo de excepciones para enfatizar el patrón.
const int BUFFER_SIZE = 4096;
static byte[] bufferForRead = new byte[BUFFER_SIZE];
static byte[] bufferForWrite = new byte[BUFFER_SIZE];
static Stream sourceStream = new MemoryStream();
static Stream destinationStream = new MemoryStream();
static void Main(string[] args)
{
// Initial read from source stream
sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}
private static void BeginReadCallback(IAsyncResult asyncRes)
{
// Finish reading from source stream
int bytesRead = sourceStream.EndRead(asyncRes);
// Make a copy of the buffer as we'll start another read immediately
Array.Copy(bufferForRead, 0, bufferForWrite, 0, bytesRead);
// Write copied buffer to destination stream
destinationStream.BeginWrite(bufferForWrite, 0, bytesRead, BeginWriteCallback, null);
// Start the next read (looks like async recursion I guess)
sourceStream.BeginRead(bufferForRead, 0, BUFFER_SIZE, BeginReadCallback, null);
}
private static void BeginWriteCallback(IAsyncResult asyncRes)
{
// Finish writing to destination stream
destinationStream.EndWrite(asyncRes);
}
Seguramente si la segunda lectura se completa antes de la primera escritura, entonces escribirá los contenidos de bufferForWrite desde la primera lectura, antes de que se escriba. –
.NET Framework 4 introduce el nuevo método "CopyTo" del espacio de nombres Stream Class of System.IO. Usando este método, podemos copiar una secuencia a otra secuencia de diferentes clases de flujo.
Aquí hay un ejemplo de esto.
FileStream objFileStream = File.Open(Server.MapPath("TextFile.txt"), FileMode.Open);
Response.Write(string.Format("FileStream Content length: {0}", objFileStream.Length.ToString()));
MemoryStream objMemoryStream = new MemoryStream();
// Copy File Stream to Memory Stream using CopyTo method
objFileStream.CopyTo(objMemoryStream);
Response.Write("<br/><br/>");
Response.Write(string.Format("MemoryStream Content length: {0}", objMemoryStream.Length.ToString()));
Response.Write("<br/><br/>");
para .NET 3.5 y antes de intentarlo:
MemoryStream1.WriteTo(MemoryStream2);
- 1. ¿Cómo copio parte de una imagen a otra?
- 2. ¿Cómo escribir el contenido de una secuencia en otra secuencia en .net?
- 3. ¿Copia de una secuencia a otra?
- 4. ¿Cómo copio un directorio de una ubicación a otra usando Ant?
- 5. Cómo convertir una secuencia de bytes a otra codificación?
- 6. ¿Cómo copiar datos binarios de una secuencia a otra?
- 7. ¿Cómo copio el contenido de una cadena al portapapeles en C#?
- 8. Copie el contenido de una columna a otra en jQuery
- 9. En SQLite, ¿cómo copio los datos de una columna a otra en la misma tabla?
- 10. ¿Cómo copio el contenido de un diccionario a un nuevo diccionario en C#?
- 11. ScalaTest: compruebe el contenido de una secuencia con ShouldMatcher
- 12. ¿Cómo copio ** kwargs a mí mismo?
- 13. Cómo copio datos binarios a un stringstream
- 14. Cómo copiar un archivo de una carpeta a otra carpeta
- 15. ¿Cómo copio un directorio a una máquina remota usando Fabric?
- 16. ¿Cómo copio una pila en Java?
- 17. Copiar el contenido y el formato de las filas (a otra hoja)
- 18. ¿Cómo copio una imagen remota en python?
- 19. cómo borrar el contenido en la secuencia de cadena.
- 20. ¿Cómo llamo a otra secuencia de comandos de PowerShell con una ruta relativa?
- 21. Cómo imprimir boost :: any a una secuencia?
- 22. obtener una longitud de contenido de la secuencia
- 23. ¿Cómo copio manualmente ensamblajes en el GAC?
- 24. ¿Cómo pasar una matriz como parámetro a otra secuencia de comandos?
- 25. Escucha en una secuencia de comandos de contenido
- 26. ¿Qué significa una secuencia de comandos con contenido src AND?
- 27. Lua - Cómo usar funciones de otra secuencia de comandos
- 28. Python: tome el contenido de una lista y añádalo a otra lista
- 29. ¿Cómo copio archivos de S3 a Amazon EMR HDFS?
- 30. MYSQL, Copie los campos seleccionados de una tabla a otra
Tal vez lo más importante en este momento, ¿Cómo copiar el contenido "streamably", lo que significa que sólo se copia la secuencia de origen como algo consume el flujo de destino ...? – drzaus