Laden...

Performance Optimierung beim Schreiben einer Textdatei

Erstellt von chip777 vor 13 Jahren Letzter Beitrag vor 13 Jahren 2.746 Views
C
chip777 Themenstarter:in
74 Beiträge seit 2010
vor 13 Jahren
Performance Optimierung beim Schreiben einer Textdatei

Hallo,

im moment benutze ich folgenden Code um Textdateien zu erstellen:


 /// <summary>
        /// Schreibt den übergebenen Text in eine definierte Zeile.
        ///</summary>
        ///<param name="sFilename">Pfad zur Datei</param>
        ///<param name="iLine">Zeilennummer</param>
        ///<param name="sLines">Text für die übergebene Zeile</param>
        ///<param name="bReplace">Text in dieser Zeile überschreiben (t) oder einfügen (f)</param>
        public void WriteLine(String sFilename, int iLine, string sLines, bool bReplace)
        {
            try
            {
                string sContent = "";
                string[] delimiterstring = { "\r\n" };

                if (File.Exists(sFilename))
                {
                    StreamReader myFile = new StreamReader(sFilename, System.Text.Encoding.UTF8);
                    sContent = myFile.ReadToEnd();
                    myFile.Close();
                }

                string[] sCols = sContent.Split(delimiterstring, StringSplitOptions.None);

                if (sCols.Length >= iLine)
                {
                    if (!bReplace)
                        sCols[iLine - 1] = sLines + "\r\n" + sCols[iLine - 1];
                    else
                        sCols[iLine - 1] = sLines;

                    sContent = "";
                    for (int x = 0; x < sCols.Length - 1; x++)
                    {
                        sContent += sCols[x] + "\r\n";
                    }
                    sContent += sCols[sCols.Length - 1];

                }
                else
                {
                    for (int x = 0; x < iLine - sCols.Length; x++)
                        sContent += "\r\n";

                    sContent += sLines;
                }
                    StreamWriter mySaveFile = new StreamWriter(sFilename);
                    mySaveFile.Write(sContent);
                    mySaveFile.Close();
                }
            }
            catch (Exception ex)
            {
                protokollierenDerFehler(ex.ToString());
            }
        }

Allerdings ist dieser Code nicht sehr performant, vielleicht hat einer von euch ja Ideen wie man das ganze verbessern könnte.

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

beschreib mal was der Code machen soll - mir ist das auf den 1. Blick nicht ganz ersichtlich und der Kommentar scheint mir nicht zum Code zu passen.

Beachte bitte auch [Hinweis] Wie poste ich richtig?

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

C
chip777 Themenstarter:in
74 Beiträge seit 2010
vor 13 Jahren

Der Code soll einen Dateinamen, eine Zeilennummer, einen Text und einen Boolschen Ausdruck annehmen.

Wenn die Datei nicht existiert wird sie angelegt und der Text in die Zeile geschrieben. Wenn bReplace true ist, wird falls in der Zeile schon Text vorhanden ist dieser überschrieben. Bei false wird der Text angehangen.

Gruß
Martin

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

wenn die Datei nicht riesig lies sie komplett in den Speicher mit


List<string> lines = File.ReadAllLines("...").ToList()

und bearbeite die Liste. Danach schreib die List<string> wieder in die Datei.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo gfoidl,

vom Prinzip macht chip777 das so. Und das Vorgehen ist wohl zu langsam. Kann ich mir auch vorstellen, zumindest wenn WriteLine oft aufgerufen wird.

Hallo chip777,

schneller wird das wohl nur gehen, wenn du die Datei nicht bei jedem Aufruf von WriteLine liest und schreibst, sondern wenn du die Datei nur einmal am Anfang liest, dann alle Änderungen im Speicher machst und die Datei erst zum Schluss wieder schreibst.

herbivore

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo herbivore,

om Prinzip macht chip777 das so.

Sehe ich nicht so. Er liest alles in einen String und bearbeitet diesen.

Dein Vorschlag ist (fast) ident zu meinem.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

49.485 Beiträge seit 2005
vor 13 Jahren

Hallo gfoidl,

mal abgesehen von dem potenziell kritischen "Schlemil the Painter"-Vorgehen beim zusammenhängen der Zeilen, sollte es ziemlich egal sein, ob man nun ReadAllLines("...").ToList() oder ReadToEnd ().Split () verwendet.

Das man die Datei dagegen nur einmal statt jedesmal liest, finde ich schon einen entscheidenden Unterschied. Falls du das auch so gemeint hattest, ist das nicht zu erkennen gewesen.

herbivore

6.911 Beiträge seit 2009
vor 13 Jahren

Hallo,

Falls du das auch so gemeint hattest, ist das nicht zu erkennen gewesen.

Ist schon so gemeint.

Um es allgemeiner zu formularieren:
Erstell ein DateiRepositoy das zu Beginn alle Zeilen in den Speicher liest und bearbeite die Zeilen im Repository (also im Speicher). Wenn sämtliche Bearbeitungsvorgänge abgeschlossen sind dann schreibe die Zeilen im Speicher auf die Platte.

Das DateiRepository kann eine einfache Klasse sein welche als Feld die List<string> zum Speichern der Zeilen hat.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

C
chip777 Themenstarter:in
74 Beiträge seit 2010
vor 13 Jahren

Ich musste erstmal Schlemiel the Painter googeln^^

Das klingt nach einer guten Idee, nur das Einlesen kann ich nicht komplett am Anfang durchführen, da es sich um Informationen handelt welche erst zur Laufzeit bereitgestellt werden, eingelesen werden immer einzelne Zeilen, keine ganze Datei. Aber ich werd das mal versuchen, zumindest das speichern nur einmal durchführen zu müssen, dass sollte die ganze Sache schon beschleunigen.

Vielen Dank für die Hilfe,

Gruß Martin

S
64 Beiträge seit 2008
vor 13 Jahren

Hallo,

ich würde evtl. die Variable sContent nicht als string, sondern als StringBuilder deklarieren. Im [Artikel] Performant Strings verketten sind einmal die verschiedenen Möglichkeiten Strings zu verketteten gegenüber gestellt. Du machst an zwei Stellen innerhalb von for-Schleifen ein

sContent += string

und das ist doch sehr unperformant.

Grüße
Maik

F
60 Beiträge seit 2010
vor 13 Jahren

Da würde ich mich nicht drauf verlassen. Oft ist String.Join schneller:
StringBuilder vs. String / Fast String Operations with .NET 2.0 - CodeProject

Übrigens würde ich mir die abart von ungarischer Notation (String sName; int iZahl;) möglichst schnell wieder abgewöhnen. Das ist kein guter Stil und erhöht den Wartungsaufwand. Du musst nämlich bei einer Typänderung im Zuge eine Refactorings zusätzlich noch die den Variablennamen ändern, was gern vergessen wird. Gerade wenns dann von Long -> Int oder so geht kann das schnell zu bugs führen. Vielleicht interessiert dich ja das Buch Clean Code.

1.820 Beiträge seit 2005
vor 13 Jahren

Hallo!

Evtl. noch als Ergänzung:
Zusätzlich könnte das Schreiben der Daten ggf. in einen Thread ausgelagert werden, wenn die Datei sonst nicht verwendet wird. Ansonsten könnte man noch den gesamten Zugriff auf die Datei über eine weitere Klasse wrappen, und diese würde dann das Schreiben der Änderungen in einem Thread starten.

Nobody is perfect. I'm sad, i'm not nobody 🙁