404 Stimmen

Was ist der schnellste Weg, eine Textdatei zeilenweise zu lesen?

Ich möchte eine Textdatei Zeile für Zeile lesen. Ich wollte wissen, ob ich es so effizient wie möglich innerhalb der .NET C# Umfang der Dinge zu tun.

Das ist es, was ich bis jetzt versucht habe:

var filestream = new System.IO.FileStream(textFilePath,
                                          System.IO.FileMode.Open,
                                          System.IO.FileAccess.Read,
                                          System.IO.FileShare.ReadWrite);
var file = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128);

while ((lineOfText = file.ReadLine()) != null)
{
    //Do something with the lineOfText
}

7voto

Marcel James Punkte 806

Es gibt ein gutes Thema zu diesem Thema in Stack Overflow Frage Ist die "Rendite" langsamer als die "Old School"-Rendite? .

Dort steht:

ReadAllLines lädt alle Zeilen in den Speicher und gibt ein string[] zurück. Alles schön und gut, wenn die Datei klein ist. Wenn die Datei größer ist, als in den Speicher passt, geht Ihnen der Speicher aus.

ReadLines hingegen verwendet yield return, um eine Zeile nach der anderen zurückzugeben zurück. Damit können Sie Dateien beliebiger Größe lesen. Es lädt nicht die ganze Datei in den Speicher.

Angenommen, Sie wollen die erste Zeile finden, die das Wort "foo" enthält, und dann beenden. Mit ReadAllLines müssten Sie die gesamte Datei lesen in den Speicher lesen, auch wenn "foo" in der ersten Zeile steht. Mit ReadLines, liest man nur eine Zeile. Was wäre schneller?

2voto

Kibbee Punkte 64039

Wenn Sie über genügend Speicher verfügen, habe ich einige Leistungssteigerungen festgestellt, indem ich die gesamte Datei in eine Erinnerungsstrom und öffnen dann einen Stream-Reader, um die Zeilen zu lesen. Solange Sie ohnehin vorhaben, die gesamte Datei zu lesen, kann dies einige Verbesserungen bringen.

2voto

jgauffin Punkte 97446

Schneller geht es nicht, wenn Sie eine vorhandene API zum Lesen der Zeilen verwenden wollen. Aber das Lesen größerer Abschnitte und das manuelle Auffinden jeder neuen Zeile im Lesepuffer wäre wahrscheinlich schneller.

-2voto

jaman Punkte 1

Wenn Sie eine Datei effizient lesen und verarbeiten müssen RIESIG Textdatei, werden ReadLines() und ReadAllLines() wahrscheinlich einen Aus dem Gedächtnis Ausnahme, das war mein Fall. Andererseits würde es ewig dauern, jede Zeile einzeln zu lesen. Die Lösung war, die Datei in Blöcken zu lesen, wie unten.

Die Klasse:

    //can return empty lines sometimes
    class LinePortionTextReader
    {
        private const int BUFFER_SIZE = 100000000; //100M characters
        StreamReader sr = null;
        string remainder = "";

        public LinePortionTextReader(string filePath)
        {
            if (File.Exists(filePath))
            {
                sr = new StreamReader(filePath);
                remainder = "";
            }
        }

        ~LinePortionTextReader()
        {
            if(null != sr) { sr.Close(); }
        }

        public string[] ReadBlock()
        {
            if(null==sr) { return new string[] { }; }
            char[] buffer = new char[BUFFER_SIZE];
            int charactersRead = sr.Read(buffer, 0, BUFFER_SIZE);
            if (charactersRead < 1) { return new string[] { }; }
            bool lastPart = (charactersRead < BUFFER_SIZE);
            if (lastPart)
            {
                char[] buffer2 = buffer.Take<char>(charactersRead).ToArray();
                buffer = buffer2;
            }
            string s = new string(buffer);
            string[] sresult = s.Split(new string[] { "\r\n" }, StringSplitOptions.None);
            sresult[0] = remainder + sresult[0];
            if (!lastPart)
            {
                remainder = sresult[sresult.Length - 1];
                sresult[sresult.Length - 1] = "";
            }
            return sresult;
        }

        public bool EOS
        {
            get
            {
                return (null == sr) ? true: sr.EndOfStream;
            }
        }
    }

Beispiel für die Verwendung:

    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length < 3)
            {
                Console.WriteLine("multifind.exe <where to search> <what to look for, one value per line> <where to put the result>");
                return;
            }

            if (!File.Exists(args[0]))
            {
                Console.WriteLine("source file not found");
                return;
            }
            if (!File.Exists(args[1]))
            {
                Console.WriteLine("reference file not found");
                return;
            }

            TextWriter tw = new StreamWriter(args[2], false);

            string[] refLines = File.ReadAllLines(args[1]);

            LinePortionTextReader lptr = new LinePortionTextReader(args[0]);
            int blockCounter = 0;
            while (!lptr.EOS)
            {
                string[] srcLines = lptr.ReadBlock();
                for (int i = 0; i < srcLines.Length; i += 1)
                {
                    string theLine = srcLines[i];
                    if (!string.IsNullOrEmpty(theLine)) //can return empty lines sometimes
                    {
                        for (int j = 0; j < refLines.Length; j += 1)
                        {
                            if (theLine.Contains(refLines[j]))
                            {
                                tw.WriteLine(theLine);
                                break;
                            }
                        }
                    }
                }

                blockCounter += 1;
                Console.WriteLine(String.Format("100 Mb blocks processed: {0}", blockCounter));
            }
            tw.Close();
        }
    }

Ich glaube, dass die Aufteilung von Strings und die Handhabung von Arrays deutlich verbessert werden kann, dennoch war das Ziel hier, die Anzahl der Lesevorgänge auf der Festplatte zu minimieren.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X