Tenho vários arquivos txt e cada arquivo contém mais de 3 milhões de linhas. Cada linha contém conexões do cliente e há ID do cliente, endereço IP....
Preciso encontrar um endereço IP específico e obter o ID do cliente relacionado a ele.
Eu li o arquivo e divido em um array e procuro em cada linha por foreach, mas como são muitas linhas, ocorre o erro abaixo.
Exceção do tipo 'System.OutOfMemoryException' foi lançada.
Devo descompactar arquivos txt, pois eles estão compactados. Eu uso o código abaixo:
string decompressTxt = decompressTxt = this.Decompress(new FileInfo(filePath));
char[] delRow = { '\n' };
string[] rows = decompressTxt.Split(delRow);
for (int i = 0; i < rows.Length; i++){
if(rows[i].Contains(ip)){
}
}
string Decompress(FileInfo fileToDecompress)
{
string newFileName = "";
string newFIleText = "";
using (FileStream originalFileStream =fileToDecompress.OpenRead())
{
string currentFileName = fileToDecompress.FullName;
newFileName = currentFileName.Remove(currentFileName.Length - fileToDecompress.Extension.Length);
using (FileStream decompressedFileStream = File.Create(newFileName))
{
using (GZipStream decompressionStream = new GZipStream(originalFileStream, CompressionMode.Decompress))
{
decompressionStream.CopyTo(decompressedFileStream);
}
}
newFIleText = File.ReadAllText(newFileName);
File.Delete(newFileName);
}
return newFIleText;
}
Ok, então há muitas coisas que você está fazendo que não são necessárias, mesmo antes de chegarmos a como você está ficando sem memória.
Primeiro, você não precisa de um arquivo intermediário para descompactar, apenas leia
GZipStream
diretamente. Mas espere, você achou que precisava usarFile.ReadAllText
para ler texto e é por isso que descompacta o arquivo primeiro?Isso é desnecessário. Quando você quiser ler o texto de um fluxo, basta usar a
StreamReader
para fazer isso (é o queFile.ReadAllText
é usado abaixo).O leitor também pode ser usado para ler linha por linha sem a necessidade de caber o arquivo inteiro na memória, apenas cada linha individual, uma de cada vez. Basta ligar
ReadLine()
até que ele retornenull
.Juntando tudo, aqui está o código que descompacta os dados e os lê uma linha por vez, sem precisar dividir nada. Ele não apenas é dimensionado com arquivos muito grandes, mas também é muito mais rápido.
Você precisa processar seu arquivo como um número de linhas. Não copie para outro
MemoryStream
nem copie em uma string.StreamReader
pode processá-lo linha por linha.Você definitivamente não precisa de outro arquivo para descompactá-lo e depois lê-lo novamente.
No total, você não precisará manter o arquivo inteiro na memória de uma só vez.
Existem métodos ainda mais eficientes, como dividir os dados em blocos de bytes, mas isso é significativamente mais complexo.
Você provavelmente também deveria pensar sobre
async
e sobre codificação.Você não precisa armazenar o arquivo inteiro na memória ou mesmo em um novo arquivo.