2 Fragen zum einlesen von Dateien
-
Hallo
ich denke, in deinem Fall ist
TProgressBar->Max = myfs->Size / myfsbuf_size;bis bald
akari
-
Danke werde das ausprobieren gleich wenn ich kann!
-
Hab jetzt Code geändert, um bekomme nun eine Zugriffsverletzung:
void __fastcall TForm1::Button1Click(TObject *Sender) { AnsiString asFileNameAndPath = "c:\\test.txt"; TFileStream *myfs = NULL; char *myfsbuf = NULL; int myfsbuf_size = 1014; int myfsbuf_read; ProgressBar1->Min = 0; ProgressBar1->Max = myfs->Size / myfsbuf_size; try { try { myfs = new TFileStream(asFileNameAndPath, fmOpenRead); myfsbuf = new char [myfsbuf_size]; myfs->Position=0; do { //RichEdit1->Lines->Text = RichEdit1->Lines->Text + AnsiString (myfsbuf); myfsbuf_read = myfs->Read((void*)myfsbuf,myfsbuf_size); ProgressBar1->Position++; Application->ProcessMessages(); } while (myfsbuf_read == myfsbuf_size); } catch(...) { ShowMessage("Fehler beim Lesen der Datei."); } } __finally { if (myfs) delete myfs; if (myfsbuf) delete[] myfsbuf; } }
-
schon mal mit dem Debugger geschaut wo die Zugriffsverletzung kommt?
woher nimmst du myfs->Size, wo du doch den FileStream noch garnicht hast?
-
Ah danke linnea
funktioniert jetzt die progressbar, fehler kommt auch ncih mehr!Dummerweise schreibst er die buchstaben immernoch untereinander im RichEdit, wie kann ich sie nebeneinander machen?
void __fastcall TForm1::Button1Click(TObject *Sender) { AnsiString asFileNameAndPath = "c:\\test.txt"; TFileStream *myfs = NULL; char *myfsbuf = NULL; int myfsbuf_size = 1014; int myfsbuf_read; try { try { myfs = new TFileStream(asFileNameAndPath, fmOpenRead); ProgressBar1->Min = 0; ProgressBar1->Max = myfs->Size / myfsbuf_size; myfsbuf = new char [myfsbuf_size]; myfs->Position=0; do { Application->ProcessMessages(); RichEdit1->Lines->Text = RichEdit1->Lines->Text + AnsiString (myfsbuf); myfsbuf_read = myfs->Read((void*)myfsbuf,myfsbuf_size); ProgressBar1->Position++; } while (myfsbuf_read == myfsbuf_size); } catch(...) { ShowMessage("Fehler beim Lesen der Datei."); } } __finally { if (myfs) delete myfs; if (myfsbuf) delete[] myfsbuf; } }und es ist verdammt langsam...!!!!
-
warum machst du das überhaupt so umständlich?
schau mal in der BCB-Hilfe unter LoadFromFile, da gibst ein schönes kleines Beispiel mit RichEdit, nur das mit dem ProgressBar brauchst du dann nicht mehr
-
Hallo
Dummerweise schreibst er die buchstaben immernoch untereinander im RichEdit, wie kann ich sie nebeneinander machen?sory, ist mein Fehler. Es muß natürlich heißen :
RichEdit1->Text = RichEdit1->Text + AnsiString (myfsbuf);bis bald
akari
-
Ich habe das Ganze jetzt mal so geändert, dass man sieht wo die Zeit verlorengeht...
Außerdem habe ich mier erlaubt den Fehler mit der Größe von myfs_buf noch zu korrigieren. Und auch noch eine Zwischenpufferung eingebaut, um die Zeilenenden erkennen zu können.
Es ist mir vor einiger Zeit schon aufgefallen, dass RichEdit im Vergleich zu StringList geradezu __quälend__ langsam ist. Wenn Du die Datei nicht, oder nur zu einem Teil anzeigen mußt...
Weiterhin habe ich noch einen zweiten Button zum Abbrechen gemacht (damit das Testen nicht so lange dauert
). Damit das funktioniert mußt Du im Header Deiner Form, unter private: noch eine Variable deklarieren: bool bAbort;void __fastcall TForm1::Button2Click(TObject *Sender) { Button1->Enabled = false; Button2->Enabled = true; AnsiString asFileNameAndPath = "c:\\test.txt"; TFileStream *myfs = NULL; TStringList* slBuffer = NULL; char *myfsbuf = NULL; int myfsbuf_size = 1024; int myfsbuf_read; AnsiString asBuffer; int pos; int iloops; bAbort = false; try { try { RichEdit1->Enabled = false; RichEdit1->Lines->Clear(); if (Button2->CanFocus()) Button2->SetFocus(); myfs = new TFileStream(asFileNameAndPath, fmOpenRead); slBuffer = new TStringList(); myfsbuf = new char [myfsbuf_size + 1]; myfs->Position=0; ProgressBar1->Position = 0; ProgressBar1->Min = 0; ProgressBar1->Max = 100; iloops = (myfs->Size / myfsbuf_size) / 100; asBuffer = ""; int iloopcount = 0; do { myfsbuf_read = myfs->Read((void*)myfsbuf,myfsbuf_size); myfsbuf[myfsbuf_read +1] = '\0'; asBuffer += AnsiString(myfsbuf); pos = asBuffer.AnsiPos("\n"); if (pos) { do { slBuffer->Add(asBuffer.SubString(1,pos - 2)); asBuffer.Delete(1, pos); pos = (asBuffer.AnsiPos("\n")); } while (pos); } iloopcount++; if (iloopcount % iloops == 0) { ProgressBar1->Position++; Application->ProcessMessages(); } } while (myfsbuf_read == myfsbuf_size && !bAbort); ProgressBar1->Position = 0; ProgressBar1->Min = 0; ProgressBar1->Max = 1000; iloops = slBuffer->Count / 1000; for (int i = 0; i < slBuffer->Count; i++) { if (bAbort) break; RichEdit1->Lines->Add(slBuffer->Strings[i]); if (i % iloops == 0) { ProgressBar1->Position++; Application->ProcessMessages(); } } RichEdit1->Enabled = true; } catch(...) { ShowMessage("Fehler beim Lesen der Datei."); } } __finally { if (myfs) delete myfs; if (myfsbuf) delete[] myfsbuf; if (slBuffer) delete slBuffer; Button1->Enabled = true; Button2->Enabled = false; } } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { bAbort = true; } //---------------------------------------------------------------------------Es sollte deutlich schneller gehen, wenn statt des zeileweisen kopierens, der Text direkt zugewiesen wird:
RichEdit1->Text = slBuffer->Text;Dann aber wieder ohne ProgessBar. Unterm Strich sollte das direkte Verwenden von LoadFromFile() die schnellste und speichergünstigste Fassung sein.
Ich, als User, wäre gerne bereit auf eine ProgressBar zu verzichten, wenn das den Vorgang um ein zigfaches beschleunigt.
-
Wow Joe!
Ich hab jetzt mal eine frage:
Kannst du mir deinen Code bitte genau erklärenwas er macht, im groben versteh ichs, aber im detail würd ich alles gern wissen, weil der richtig gut funkt!
Wäre supernett, aber wenns zu viele Umstände macht is auch nich schlimm!
-
Nein es macht keine Umstände, ausserdem lernst Du nix dabei, nur Code abzutippen, den Du nicht verstehst.
Wie gesagt habe ich nur ein paar Änderungen vorgenommen. Ich mach mal ein paar Remarks an die interessanten Stellen.
try { try { RichEdit1->Enabled = false; // wenn das RE den Fokus hat und die ScrollBars aktiv sind geht es noch langsamer RichEdit1->Lines->Clear(); if (Button2->CanFocus()) Button2->SetFocus(); // deswegen Fokus auf etwas anderes setzen, sinnvollerweise der Abbrechen-Button myfs = new TFileStream(asFileNameAndPath, fmOpenRead); slBuffer = new TStringList(); myfsbuf = new char [myfsbuf_size + 1]; // da als char weiterverwendet, muus am Ende noch Platz für ein abschliessendes \0 sein myfs->Position=0; ProgressBar1->Position = 0; ProgressBar1->Min = 0; ProgressBar1->Max = 100; // es macht keinen Sinn, eine Progressbar 25 Millionen mal zu aktualisieren... kostet nur unnötig Zeit iloops = (myfs->Size / myfsbuf_size) / 100; // wir haben 100 Steps für die PG, also alle iloops einmal Position++. asBuffer = ""; // AnsiString-Puffer leeren int iloopcount = 0; do { myfsbuf_read = myfs->Read((void*)myfsbuf,myfsbuf_size); myfsbuf[myfsbuf_read +1] = '\0'; // nach den eingelesenen Zeichen den char-Terminanator anhängen asBuffer += AnsiString(myfsbuf); pos = asBuffer.AnsiPos("\n"); // erstes Zeilenende suchen if (pos) // Zeilenende vorhanden? { do { slBuffer->Add(asBuffer.SubString(1,pos - 2)); // Zeile in String List einfügen. Das Zeilenende selbst darf nicht übernommen werden (pos - 2) asBuffer.Delete(1, pos); // und aus Puffer löschen pos = (asBuffer.AnsiPos("\n")); // noch ein Zeilenende in asBuffer? } while (pos); // solange bis keine Zeilenenden mehr im Puffer sind } iloopcount++; if (iloopcount % iloops == 0) // ProgessBar erhöhen? { ProgressBar1->Position++; Application->ProcessMessages(); // sollte auch nicht zu oft aufgerufen werden. } } while (myfsbuf_read == myfsbuf_size && !bAbort); // ab hier wird einfach nur der Inhalt der StringList auf die ungünstigste Art in das RichEdit kopiert // diente auch eigentlich nur zur Illustration, wo die Zeit verloren geht. RichEdit1->Enabled = true; } catch(...) { ShowMessage("Fehler beim Lesen der Datei."); } }Kannst Du so etwas damit anfangen, wenn nicht: Frag nochmal!
Ach so, das manuelle Trennen der Strings durch Suchen des Zeilenendes habe ich nur gemacht, weil ich dachte, dass das Anhängen von Zeilen über ->Lines->Add() schneller sein würde, als das Anhängen des Textes über ->Text = ->Text + String. Ich habe da allerdings keinen großen Unterschied feststellen können.
if (iloopcount % iloops == 0)
wenn iloopcount modulo iloops = 0 ist, entspricht iloopcount einem vielfachen (1, 2, 3, 4 ... 100) von iloops. Ich weiß nicht wie ich das besser erklären soll. Hintergrund ist einfach nur, dass es viel zu viel Rechenzeit kostet, bei jedem Schleifendurchlauf die ProgressBar->Position zu erhöhen und die Nachrichtenschlange abzuarbeiten. Hier gibt es keinen sinnvollen Vorgabewert. Man muss schauen wie oft so etwas nötig ist, damit die Anwendung ansprechbar bleibt, aber dabei nicht unnötig Rechenzeit verbrät.Außerdem habe ich bei dem asBuffer-Aufdröseln einen dummen Logikfehler gemacht. Findest Du den? (Hinweis: Die Routine als solches ist in Ordnung aber es fehlt noch etwas nach dem allerletzten Durchlauf...)
-
Nochmal WOW Joe....hab es mir erst einmal durchgelesen, alles versteh ich nicht, sobald ich aber wieder auf arbeit bin druck ich mir das aus und les es mir so oft durch bis ich es kapier...und den Logikfehler hab ich NOCH nicht gefunden...
DANKE erstmal

-
Was genau verstehst Du denn nicht?
-
Das erzähl ich dir, wenn ich es nach dem 3ten mal lesen und testen nicht verstehe! ok??