Eu tenho um servidor web que lê grandes arquivos binários (vários megabytes) em matrizes de bytes. O servidor pode estar lendo vários arquivos ao mesmo tempo (solicitações de página diferentes), por isso estou procurando a maneira mais otimizada de fazer isso sem sobrecarregar demais a CPU. O código abaixo é bom o suficiente?
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
fonte
fonte
byte[] buff = File.ReadAllBytes(fileName)
.Respostas:
Simplesmente substitua a coisa toda por:
No entanto, se você está preocupado com o consumo de memória, você deve não ler o arquivo inteiro na memória de uma só vez a todos. Você deve fazer isso em pedaços.
fonte
Eu poderia argumentar que a resposta aqui geralmente é "não". A menos que você precise absolutamente de todos os dados de uma vez, considere usar uma
Stream
API baseada em (ou alguma variante do leitor / iterador). Isso é especialmente importante quando você tem várias operações paralelas (conforme sugerido pela pergunta) para minimizar a carga do sistema e maximizar a taxa de transferência.Por exemplo, se você estiver transmitindo dados para um chamador:
fonte
byte[]
por algum motivo, sugiro evitar o uso de fluxos ou qualquer outra coisa e apenas usar a API fornecida pelo sistema.File.ReadAllBytes
.Eu pensaria o seguinte:
fonte
Seu código pode ser fatorado para isso (em vez de File.ReadAllBytes):
Observe a limitação de tamanho de arquivo Integer.MaxValue colocada pelo método Read. Em outras palavras, você pode ler apenas um pedaço de 2 GB de uma vez.
Observe também que o último argumento para o FileStream é um tamanho de buffer.
Eu também sugeriria ler sobre o FileStream e BufferedStream .
Como sempre, um programa de amostra simples para definir o perfil mais rápido será mais benéfico.
Além disso, seu hardware subjacente terá um grande efeito no desempenho. Você está usando unidades de disco rígido baseadas em servidor com caches grandes e uma placa RAID com cache de memória integrado? Ou você está usando uma unidade padrão conectada à porta IDE?
fonte
var binaryReader = new BinaryReader(fs); fileData = binaryReader.ReadBytes((int)fs.Length);
nessausing
afirmação. Mas isso é efetivamente o que o OP fez, apenas recortei uma linha de código convertendofs.Length
para, emint
vez de obter olong
valor doFileInfo
comprimento e convertê-lo.Dependendo da frequência das operações, do tamanho dos arquivos e do número de arquivos que você está visualizando, há outros problemas de desempenho a serem considerados. Uma coisa a lembrar é que cada uma de suas matrizes de bytes será liberada à mercê do coletor de lixo. Se você não estiver armazenando em cache nenhum desses dados, poderá criar muito lixo e perder a maior parte do seu desempenho para % Time in GC. Se os pedaços forem maiores que 85K, você estará alocando para o Large Object Heap (LOH), que exigirá a liberação de uma coleção de todas as gerações (isso é muito caro e o servidor interromperá toda a execução enquanto estiver acontecendo) ) Além disso, se você tiver vários objetos no LOH, poderá acabar com a fragmentação do LOH (o LOH nunca é compactado), o que leva a um desempenho ruim e a exceções de falta de memória. Você pode reciclar o processo depois de atingir um determinado ponto, mas não sei se essa é uma prática recomendada.
O ponto é que você deve considerar o ciclo de vida completo do seu aplicativo antes de necessariamente ler todos os bytes na memória da maneira mais rápida possível ou pode estar trocando desempenho de curto prazo pelo desempenho geral.
fonte
garbage collector
,chunks
, desempenho, contadores de eventos , ...Eu diria que
BinaryReader
está bem, mas pode ser refatorado para isso, em vez de todas essas linhas de código para obter o comprimento do buffer:Deveria ser melhor do que usar
.ReadAllBytes()
, já que vi nos comentários a resposta principal que inclui.ReadAllBytes()
que um dos comentaristas teve problemas com arquivos> 600 MB, já que aBinaryReader
destina-se a esse tipo de coisa. Além disso, colocando-o em umausing
declaração assegura aFileStream
eBinaryReader
está fechado e descartado.fonte
new
não era necessário lá. Removido.No caso de "um arquivo grande", além do limite de 4 GB, minha lógica de código escrita a seguir é apropriada. O principal problema a ser observado é o tipo de dados LONG usado com o método SEEK. Como um LONG, é capaz de apontar além de 2 ^ 32 limites de dados. Neste exemplo, o código está processando primeiro o processamento do arquivo grande em pedaços de 1 GB, depois que os pedaços grandes de 1 GB são processados, os bytes restantes (<1 GB) são processados. Eu uso esse código para calcular o CRC de arquivos além do tamanho de 4 GB. (usando https://crc32c.machinezoo.com/ para o cálculo crc32c neste exemplo)
fonte
Use a classe BufferedStream em C # para melhorar o desempenho. Um buffer é um bloco de bytes na memória usado para armazenar dados em cache, reduzindo assim o número de chamadas para o sistema operacional. Os buffers melhoram o desempenho de leitura e gravação.
Consulte o seguinte para obter um exemplo de código e explicação adicional: http://msdn.microsoft.com/en-us/library/system.io.bufferedstream.aspx
fonte
BufferedStream
quando você está lendo a coisa toda de uma só vez?usa isto:
fonte
Visão geral: se sua imagem for adicionada como um recurso action = incorporado, use o GetExecutingAssembly para recuperar o recurso jpg em um fluxo e leia os dados binários no fluxo em uma matriz de bytes
fonte
Eu recomendaria tentar o
Response.TransferFile()
método, em seguida, umResponse.Flush()
eResponse.End()
para servir seus arquivos grandes.fonte
Se você estiver lidando com arquivos acima de 2 GB, verá que os métodos acima falham.
É muito mais fácil enviar o fluxo para o MD5 e permitir que você divida seu arquivo para você:
fonte