Tengo un servidor web que leerá archivos binarios grandes (varios megabytes) en conjuntos de bytes. El servidor podría estar leyendo varios archivos al mismo tiempo (solicitudes de página diferentes), por lo que estoy buscando la forma más optimizada para hacerlo sin gravar demasiado la CPU. ¿El código a continuación es lo suficientemente bueno?
public byte[] FileToByteArray(string fileName)
{
byte[] buff = null;
FileStream fs = new FileStream(fileName,
FileMode.Open,
FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
long numBytes = new FileInfo(fileName).Length;
buff = br.ReadBytes((int) numBytes);
return buff;
}
c#
.net
bytearray
binary-data
Tony_Henrich
fuente
fuente
byte[] buff = File.ReadAllBytes(fileName)
.Respuestas:
Simplemente reemplace todo con:
Sin embargo, si usted está preocupado por el consumo de memoria, debe no leer todo el archivo en memoria a la vez a todos. Deberías hacer eso en trozos.
fuente
Podría argumentar que la respuesta aquí generalmente es "no". A menos que necesite absolutamente todos los datos a la vez, considere usar una
Stream
API basada en (o alguna variante de lector / iterador). Es decir especialmente importante cuando tiene múltiples operaciones paralelas (como lo sugiere la pregunta) para minimizar la carga del sistema y maximizar el rendimiento.Por ejemplo, si está transmitiendo datos a una persona que llama:
fuente
byte[]
por algún motivo, le sugiero que evite usar transmisiones o cualquier otra cosa y simplemente use la API proporcionada por el sistema.File.ReadAllBytes
.Yo pensaría esto:
fuente
Su código se puede tener en cuenta para esto (en lugar de File.ReadAllBytes):
Tenga en cuenta el Integer.MaxValue: limitación de tamaño de archivo establecida por el método Read. En otras palabras, solo puedes leer un fragmento de 2GB a la vez.
También tenga en cuenta que el último argumento para FileStream es un tamaño de búfer.
También sugeriría leer sobre FileStream y BufferedStream .
Como siempre, un programa de muestra simple para perfilar que es el más rápido será el más beneficioso.
Además, su hardware subyacente tendrá un gran efecto en el rendimiento. ¿Está utilizando unidades de disco duro basadas en servidor con cachés grandes y una tarjeta RAID con memoria caché integrada? ¿O está utilizando una unidad estándar conectada al puerto IDE?
fuente
var binaryReader = new BinaryReader(fs); fileData = binaryReader.ReadBytes((int)fs.Length);
en esausing
declaración. Pero eso es efectivamente lo que hizo el OP, solo corté una línea de código al convertirlofs.Length
enint
lugar de obtener ellong
valor de laFileInfo
longitud y convertirlo.Dependiendo de la frecuencia de las operaciones, el tamaño de los archivos y la cantidad de archivos que está viendo, hay otros problemas de rendimiento a tener en cuenta. Una cosa para recordar es que cada una de sus matrices de bytes se liberará a merced del recolector de basura. Si no está almacenando en caché ninguno de esos datos, podría terminar creando mucha basura y perdiendo la mayor parte de su rendimiento por % de tiempo en GC. Si los fragmentos son más grandes que 85K, se asignará al Montón de objetos grandes (LOH) que requerirá una colección de todas las generaciones para liberarse (esto es muy costoso, y en un servidor detendrá toda ejecución mientras continúa) ) Además, si tiene una tonelada de objetos en el LOH, puede terminar con la fragmentación de LOH (el LOH nunca se compacta), lo que conduce a un rendimiento deficiente y excepciones de falta de memoria. Puede reciclar el proceso una vez que llegue a cierto punto, pero no sé si es una buena práctica.
El punto es que debe considerar el ciclo de vida completo de su aplicación antes de simplemente leer todos los bytes en la memoria de la manera más rápida posible o podría estar intercambiando el rendimiento a corto plazo por el rendimiento general.
fuente
garbage collector
,chunks
, rendimiento, contadores de eventos , ...Diría que
BinaryReader
está bien, pero se puede refactorizar a esto, en lugar de todas esas líneas de código para obtener la longitud del búfer:Debería ser mejor que usar
.ReadAllBytes()
, ya que vi en los comentarios en la respuesta superior que incluye.ReadAllBytes()
que uno de los comentaristas tuvo problemas con archivos> 600 MB, ya queBinaryReader
está destinado a este tipo de cosas. Además, poniéndola en unusing
comunicado asegura que elFileStream
yBinaryReader
están cerrados y eliminados.fuente
new
no era necesario allí. Remoto.En caso de que 'un archivo grande' signifique más allá del límite de 4 GB, entonces mi siguiente lógica de código escrito es apropiada. La cuestión clave a tener en cuenta es el tipo de datos LARGO utilizado con el método SEEK. Como LONG es capaz de apuntar más allá de 2 ^ 32 límites de datos. En este ejemplo, el código procesa procesando primero el archivo grande en fragmentos de 1 GB, después de que se procesan los fragmentos enteros grandes de 1 GB, se procesan los bytes restantes (<1 GB). Utilizo este código para calcular el CRC de archivos más allá del tamaño de 4 GB. (usando https://crc32c.machinezoo.com/ para el cálculo de crc32c en este ejemplo)
fuente
Use la clase BufferedStream en C # para mejorar el rendimiento. Un búfer es un bloque de bytes en la memoria que se usa para almacenar en caché los datos, lo que reduce la cantidad de llamadas al sistema operativo. Los buffers mejoran el rendimiento de lectura y escritura.
Consulte lo siguiente para ver un ejemplo de código y una explicación adicional: http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx
fuente
BufferedStream
cuando estás leyendo todo de una vez?utilizar este:
fuente
Descripción general: si su imagen se agrega como un recurso acción = incrustado, use GetExecutingAssembly para recuperar el recurso jpg en una secuencia y luego lea los datos binarios de la secuencia en una matriz de bytes
fuente
Recomiendo probar el
Response.TransferFile()
método a continuación, unaResponse.Flush()
yResponse.End()
para servir a sus archivos de gran tamaño.fuente
Si está tratando con archivos de más de 2 GB, encontrará que los métodos anteriores fallan.
Es mucho más fácil simplemente pasar la transmisión a MD5 y permitir que fragmente el archivo por usted:
fuente