Größere Datei Stückweise einlesen



  • Hallo Leute,

    ich habe eine ca. 150 MB große CSV Datei, die ich gerne Stückweise einlesen möchte. Am besten wären im Stückweise 20 Zeilen, die ich dann verarbeite und danach die nächsten 20 Zeilen lesen.

    Ich denke, wenn ich die ganze Datei in eine StringListe lade, wird das nicht gehen. Nur habe ich keine Idee wie ich das mit dem Stückweisen einlesen machen sollte. Hat da irgendwer eine Idee?

    jendrik



  • Hallo

    dazu kannst du ifstream aus der STL benutzen. Damit kann man ganz gezielt einzele Zeichen einlesen: Schau einfach mal in die BCB-Hilfe zu ifsteam bzw. basic_ifstream, dort ist auch ein Beispiel. Oder such einfach im C++ Forum nach ifstream...

    bis bald
    akari



  • Hi,

    habe mal was probiert:

    #include<iostream>
    #include<fstream>
    #include<iomanip>
    
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       std::ifstream F1;
       char c_line[2000];
       String line;
    
       F1.open(EFile->Text, ios_base::in);
       while (F1.getline(c_line))
       {
          line=c_line;
       }
       F1.close();
    }
    

    Muss mir aber leider Fehler anhören:

    [C++ Fehler] main.cpp(26): E2090 Qualifizierer 'ios_base' ist kein Name einer Klasse oder einer Struktur
    [C++ Fehler] main.cpp(26): E2121 ) fehlt beim Funktionsaufruf
    [C++ Fehler] main.cpp(27): E2285 Keine Übereinstimmung für 'std::istream::getline(char *)' gefunden

    Jemand eine Idee?

    jendrik



  • Hallo

    2 Fehler :

    using namespace std;
    

    nach den Includes vergessen (dafür kannst du alle anderen std:: weglassen)
    - statt

    while (F1.getline(c_line))
    

    nimm

    while (F1 >> c_line)
    

    außerdem empfehle ich dir, char [2000] durch std::string (kleingeschrieben) zu ersetzen.

    bis bald
    akari



  • Hi,

    ich habe meinen code nun geändert um eine datei zeilen weise einzulesen. problem ist das jede eingelesene zeile nun eine länge von 2048 zeichen hat. wenn eine zeile allerdings nur mal aus wenigen wörter besteht, ist mein String einfach zu lang. Habe es mit Trim versucht um alle Leerzeichen zu kicken, das bringt aber auch keine Lösung, denn so ist jeder String 343 Zeichen lang. Was muss ich machen, damit in dem String auch nur der Text der Zeile drinnen ist und keine Leerzeichen. Habe die max Länge nur auf 2048 gesetzt, damit auch lange Zeilen eingelesen werden können.

    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       // Setup
       const int bufSize=2048;
       int zeile = 0;
       String linebuf;
       String line;
       linebuf.SetLength(bufSize);
    
       // Open File
       ifstream ifs(EFile->Text.c_str());
       if(ifs)
       {
          while(true)
          {
             // Stop when need
             if (abbruch == true) break;
    
             // Read the line
             zeile++;
             ifs.getline(linebuf.c_str(),bufSize);
             line = linebuf;
             // line = Trim(linebuf);
    
             // Dies hier ist immer Zulang
             Memo1->Lines->Add(line.Length());
    
             if (zeile == 10) break;
    
             // Anwendung nicht abstürzen lassen
             Application->ProcessMessages();
    
             // Bei Zeilenende stoppen
             if(ifs.eof())
                break;
    
             if(!ifs.gcount())
             {
                ShowMessage("buffer too small or non-textfile");
                break;
             }
          }
    
          ifs.close();
      }
    
    }
    

    Weiß irgendwie nicth weiter.

    Jendrik



  • Hallo

    damit kannst du eine ganze Datei sauber zeilenweise einlesen, und bekommst noch die Anzahl Zeichen pro Zeile und die Anzahl Zeilen. Übrigens ist das kein BCB-Thema meht, sondern gehärt bereits ins C++ Forum

    int zeile = 0; // Anzahl Zeilen
    int charcount; // Anzahl Zeichen in aktueller Zeile
    string line; // aktuelle Zeile
    char Buffer; // einzelnes Zeichen zum Lesen
    
    ifstream ifs("Test.dat"); // Open File
    
    // Alle Zeichen aus Datei lesen
    while (ifs.get(Buffer))
    {
    
      // Wenn Zeilenumbruch, Zeile abschließen und ausgeben
      if (Buffer == '\n')
      {
        Memo1->Lines->Add(IntToStr(line.size()) + ":" + line.c_str()); // Kontrollausgabe
        line = ""; // Zeile leeren
        zeile++; // Zeilenanzahl erhöhen
        }
    
      // Wenn kein Zeilenumbruch, Zeichen an Zeile anhängen
      else
      {
        line += Buffer;
        }
      }
    
    // Wenn letzte Zeile vorhanden, diese ebenfalls ausgeben und berechnen
    if (line != "")
    {
      Memo1->Lines->Add(IntToStr(line.size()) + ":" + line.c_str());
      line = "";
      zeile++;
      }
    Memo1->Lines->Add(IntToStr(zeile)); // Anzahl Zeilen ausgeben
    
    ifs.close(); // Datei schließen
    

    bis bald
    akari



  • akari schrieb:

    Übrigens ist das kein BCB-Thema meht, sondern gehärt bereits ins C++ Forum

    Warum kramst du dann erst ifstream raus, anstatt z.B. TFileStream vorzuschlagen? 😉



  • Hallo

    Warum kramst du dann erst ifstream raus, anstatt z.B. TFileStream vorzuschlagen?

    Okay, das ganze kann man auch mit TFileStream umzusetzen sein (sollte recht ähnlich sein, habe mal die Funktion überflogen).
    ifstream hat natürlich den Vorteil, das man etwas Standard-C++ lernt, das man auch auf anderen Compilern/ Platformen anwenden kann.

    bis bald
    akari



  • Hallo akari,

    ich wollte eben mal deinen code ausprobieren. Leider bekomme ich eine Fehlermelung bei folgender Zeile:

    Memo1->Lines->Add(IntToStr(line.size()) + ":" + line.c_str());
    

    Die Fehlermeldung lautet: 'size' ist kein Element von 'AniString'.

    Habe ich da was falsch gemacht oder liegt der Fehler bei deinem Code.

    Vielleicht könntest mir da weiterhelfen. Wäre super.

    Gruß
    EPMS



  • Hallo

    statt size() mußt du Length() nehmen. Steht aber auch in der BCB-Hilfe.
    (in meinem Beispiel hatte ich string statt AnsiString/String genommen. Das ist nicht das selbe, aber du kannst auch das nehmen)

    /edit : Beim nochmal durchlesen des Threads stelle ich fest, das du eher AnsiString/String durch string ersetzen solltest

    bis bald
    akari



  • Also da das hier das BCB-Forum ist, würde ich die Verwendung von AnsiString und TFileStream empfehlen. (ich will nix über C(++)-Konformität oder Standard-C(++) hören - sonst hätte ich mir wohl kaum den BCB zugelegt 😉 ).

    Desweiteren ist das zeichenweise Einlesen einer Datei quälend langsam. Sinnvoller ist, größere Stücke der Datei in einen Puffer einzulesen, und den Puffer auszuwerten.

    Wie das geht, hab' ich hier schon mal irgendwo gepostet. Such mal nach TFileStream.



  • Ich danke euch beiden.
    @akari, hat wunderbar geklappt.
    @Joe_M., werde mir mal TFileStream anschauen.

    Danke schön
    Gruß
    EPMS


Log in to reply