Hoe lees ik een groot (1 GB) txt-bestand in .NET?

Ik heb een tekstbestand van 1 GB dat ik regel voor regel moet lezen. Wat is de beste en snelste manier om dit te doen?

private void ReadTxtFile()
{            
    string filePath = string.Empty;
    filePath = openFileDialog1.FileName;
    if (string.IsNullOrEmpty(filePath))
    {
        using (StreamReader sr = new StreamReader(filePath))
        {
            String line;
            while ((line = sr.ReadLine()) != null)
            {
                FormatData(line);                        
            }
        }
    }
}

In FormatData()controleer ik het beginwoord van de regel die moet worden gekoppeld aan een woord en op basis daarvan een integer-variabele verhogen.

void FormatData(string line)
{
    if (line.StartWith(word))
    {
        globalIntVariable++;
    }
}

Antwoord 1, autoriteit 100%

Als je .NET 4.0 gebruikt, probeer dan MemoryMappedFile wat een ontworpen klasse is voor dit scenario.

U kunt StreamReader.ReadLineanders gebruiken.


Antwoord 2, autoriteit 60%

Het is waarschijnlijk de beste manier om StreamReader te gebruiken, aangezien u niet het hele bestand in één keer in het geheugen wilt hebben. MemoryMappedFile is meer bedoeld voor willekeurige toegang dan sequentieel lezen (het is tien keer zo snel voor sequentiële lezing en geheugentoewijzing is tien keer zo snel voor willekeurige toegang).

U kunt ook proberen uw streamreader te maken vanuit een bestandsstream met FileOptions ingesteld op SequentialScan (zie FileOptions Enumeration), maar ik betwijfel of het veel verschil zal maken.

Er zijn echter manieren om uw voorbeeld effectiever te maken, aangezien u uw opmaak in dezelfde lus uitvoert als bij het lezen. Je verspilt klokcycli, dus als je nog meer prestaties wilt, zou het beter zijn met een asynchrone oplossing met meerdere threads, waarbij de ene thread gegevens leest en de andere deze formatteert zodra deze beschikbaar komen. Afrekenen BlockingColletion die mogelijk aan uw behoeften voldoet:

Verzameling blokkeren en het probleem producent-consument

Als je de snelst mogelijke prestaties wilt, is mijn ervaring de enige manier om een ​​zo groot mogelijk stuk binaire gegevens opeenvolgend in te lezen en deze parallel in tekst te deserialiseren, maar de code begint op dat punt ingewikkeld te worden.

p>


Antwoord 3, autoriteit 31%

U kunt LINQgebruiken:

int result = File.ReadLines(filePath).Count(line => line.StartsWith(word));

File.ReadLinesretourneert een IEnumerable<String>die lui elke regel uit het bestand leest zonder het hele bestand in het geheugen te laden.

Enumerable.Counttelt de regels die beginnen met het woord.

Als je dit vanuit een UI-thread aanroept, gebruik dan een BackgroundWorker.


Antwoord 4, autoriteit 19%

Waarschijnlijk om het regel voor regel.

Je moet liever niet proberen het in het geheugen te forceren door tot het einde te lezen en vervolgens te verwerken.


Antwoord 5, autoriteit 15%

StreamReader.ReadLinezou goed moeten werken. Laat het framework de buffering kiezen, tenzij je weet dat je door te profileren beter kunt doen.


Antwoord 6, autoriteit 12%

TextReader.ReadLine()


Antwoord 7, autoriteit 2%

Ik had hetzelfde probleem in onze productieserver bij Agentywaar we grote bestanden zien (soms 10- 25 GB (\t) door tabs gescheiden txt-bestanden). En na veel testen en onderzoek vond ik de beste manier om grote bestanden in kleine stukjes te lezen met de for/foreach-lus en het instellen van offset en limietlogica met File.ReadLines().

int TotalRows = File.ReadLines(Path).Count(); // Count the number of rows in file with lazy load
int Limit = 100000; // 100000 rows per batch
for (int Offset = 0; Offset < TotalRows; Offset += Limit)
{
  var table = Path.FileToTable(heading: true, delimiter: '\t', offset : Offset, limit: Limit);
 // Do all your processing here and with limit and offset and save to drive in append mode
 // The append mode will write the output in same file for each processed batch.
  table.TableToFile(@"C:\output.txt");
}

Bekijk de volledige code in mijn Github-bibliotheek: https://github.com/Agenty/FileReader/

Volledige openbaarmaking – ik werk voor Agenty, het bedrijf dat eigenaar was van deze bibliotheek en website


Antwoord 8, autoriteit 2%

Mijn bestand is groter dan 13 GB:

voer hier de afbeeldingsbeschrijving in

Je kunt mijn klas gebruiken:

public static void Read(int length)
    {
        StringBuilder resultAsString = new StringBuilder();
        using (MemoryMappedFile memoryMappedFile = MemoryMappedFile.CreateFromFile(@"D:\_Profession\Projects\Parto\HotelDataManagement\_Document\Expedia_Rapid.jsonl\Expedia_Rapi.json"))
        using (MemoryMappedViewStream memoryMappedViewStream = memoryMappedFile.CreateViewStream(0, length))
        {
            for (int i = 0; i < length; i++)
            {
                //Reads a byte from a stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
                int result = memoryMappedViewStream.ReadByte();
                if (result == -1)
                {
                    break;
                }
                char letter = (char)result;
                resultAsString.Append(letter);
            }
        }
    }

Deze code leest de tekst van het bestand vanaf het begin tot de lengte die u doorgeeft aan de methode Read(int length)en vult de variabele resultAsString in.

Het geeft de onderstaande tekst terug:


Antwoord 9

Ik zou het bestand 10.000 bytes per keer lezen. Vervolgens analyseerde ik die 10.000 bytes, hakte ze in regels en voerde ze door naar de FormatData-functie.

Bonuspunten voor het splitsen van de lezing en lijnanalyse op meerdere threads.

Ik zou zeker een StringBuilderom alle strings te verzamelen en kan een stringbuffer bouwen om de hele tijd ongeveer 100 strings in het geheugen te bewaren.

Other episodes