Textdatei einlesen

  • Textdatei einlesen

    Hallo an alle,

    Ich habe eine Textdatei (.txt) die ich Zeile für Zeile einlesen will.
    Dabei sind die ersten drei Werte, die durch Komma getrennt sind, Zahlen(double) und das letzte ein String.

    101.28708 ,-16.71611, -1.46, Sirius
    95.98792, -52.69583,-0.72, Canopus
    213.91542, 19.1825, -0.04, Arcturus
    ....

    Wie kann ich die Werte Zeile per Zeile einlesen (von oben nach unten) und die Werte in ein Variablenarray schreiben ?


    gruß Don
  • Mit dem NSScanner macht man sowas.
    Ich habe dabei erst die ganze Textdatei in einen NSString gepackt und diesen dann mit dem NSScanner geparst.
    Mithilfe von NSCharacterSets kannst du dann z. B. auch sagen dass er einlesen soll bis er ein bestimmtes Zeichen findet. bei dir wäre das dann entweder Komma oder Leerzeichen. Die Zeilen kann man dabei eigentlich ignorieren.
    Das blöde ist aber dass deine Zahlen einen Punkt beinhalten. Den musst du, denke ich, erst rausfiltern bevor du die Zahl in einem double speichern kannst.
  • RE: Textdatei einlesen

    Wenn die Struktur derart einheitlich ist (und bleibt), dann geht auch:

    Quellcode

    1. NSString *s=[NSString stringWithContentsOfFile:@"... file path..."];
    2. NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    3. NSEnumerator *e=[lines objectEnumerator];
    4. NSString *line;
    5. while((line=[e nextObject]))
    6. {
    7. NSArray *components=[line componentsSeparatedByString:@","];
    8. // componentns verarbeiten...
    9. }


    -- hns
  • Original von MetalSnake
    Das blöde ist aber dass deine Zahlen einen Punkt beinhalten. Den musst du, denke ich, erst rausfiltern bevor du die Zahl in einem double speichern kannst.

    M.E. nicht.
    -scanDouble liest den Punkt mit sofern er vorhanden ist und kümmert sich um die korrekte Umwandlung. Wo sollte da ein Problem dabei sein?

    -- hns
  • Original von hns
    Original von MetalSnake
    Das blöde ist aber dass deine Zahlen einen Punkt beinhalten. Den musst du, denke ich, erst rausfiltern bevor du die Zahl in einem double speichern kannst.

    M.E. nicht.
    -scanDouble liest den Punkt mit sofern er vorhanden ist und kümmert sich um die korrekte Umwandlung. Wo sollte da ein Problem dabei sein?

    -- hns


    Wusste ich nicht, war mir da auch nicht wirklich sicher, deswegen das eingeschobene "denke ich".
  • Hallo MetalSnake und hns,

    Ich wollte mich an dieser Stelle schonmal bedanken für eure Hilfestellung.
    Ich habe allg. noch sehr viele Probleme mt Objective-C da ich eben noch ziemlicher Neuling bin.

    Bzgl. der Punkt und Komma Geschichte kann ich nur sagen, das ich das Problem von VisualBasic(Windows) kenne. In England ist der Punkt das Dezimaltrennzeichen und bei uns ist es das Komma. Also: englisch 1000.00 (eintausend) , deutsch 1000,00 (eintausend)

    Ich versuche mal das Beispiel was du hns geschickt hast zu erklären,
    wenn du Lust hast oder magst kannst mich ja korrigieren. Also ich leg mal los...
    (Daran kannst du sehen wie ich das "denke" und kannst mich evtl. dezidiert korrigieren)

    NSString *s=[NSString stringWithContentsOfFile:@"... file path..."];
    //definierst einen String "s" von NSString, gleichzeitig benutzt du die Methode stringWithContensOfFile(in etwa "alles einlesen") und gibst hinter dem @ den Pfad an.


    NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    //Definierst du das Array "lines" benutz die Methode componentsSeparatedByString "n"(Wo ist eigentlich dieser andere Schrägstrich vor dem n?Ich hab ein iBook?Tastenkombi?)

    NSEnumerator *e=[lines objectEnumerator];
    //Hier weiss ich nicht genau was du machst?

    NSString *line;
    //Hier definirst du die "line" als String

    while((line=[e nextObject]))
    //Hier komm ich auch nicht ganz mit, "line" ist wohl der String, aber da "e" versteh ich nicht, den Typ NSEnumerator kenn ich nicht?Die Schleicfe stoppt wenn es kein "nextObject" mehr gibt?
    {
    NSArray *components=[line componentsSeparatedByString:@","];
    //mit componentsSeparatedByString separierst du sie durch nach ","
    // componentns verarbeiten...

    }

    Ich weiss das man viele Dinge in der Programmierung selbst ausporbieren muss, das ist in etwa so wie Autofahren, doch da ich jahrelang in VisualBasic Programmiert hab und nun Cocoa lernen möchte, hatte ich mir gedacht vorab logische Zusammenhänge und den Syntax der Sprache sozusagen (theoretisch) zu lernen. Ich denke mir, manchmal erspart es sich etwas "rumprobieren" wenn man genauer versteht was gemeint ist und wie es funktioniert.Cocoa ist im vergleich zu VisualBasic viel schwerer finde ich aber nach meinem ersten Eindrücken eine sehr elegante,schöne Sprache.
    Diese Textdatei ist übrigens eine Sterndatenbank

    gruß Don
  • Original von donadm
    NSString *s=[NSString stringWithContentsOfFile:@"... file path..."];
    //definierst einen String "s" von NSString, gleichzeitig benutzt du die Methode stringWithContensOfFile(in etwa "alles einlesen") und gibst hinter dem @ den Pfad an.

    Stimmt. Das Ergebnis ist eine Instanz von NSString mit dem Inhalt der angegebenen Datei.

    Original von donadm
    NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    //Definierst du das Array "lines" benutz die Methode componentsSeparatedByString "n"(Wo ist eigentlich dieser andere Schrägstrich vor dem n?Ich hab ein iBook?Tastenkombi?)

    Stimmt auch. Das Ergebnis ist eine NSArray-Instanz, die den String s in einzelne Zeilen aufgeteilt "enthält". Der Backslash ist mit Alt-Shift-7 erreichbar. Du kannst Dir übrigens eine Tastaturübersicht einblenden, auf der Du dann sehen kannst, wie die Tasten belegt sind. Dazu musst Du in den Systemeinstellungen->Landeseinstellungen->Tastaturmenü die Anzeige in der Menüleiste einschalten und natürlich auch die Tastaturübersicht anhaken.

    Original von donadm
    NSEnumerator *e=[lines objectEnumerator];
    //Hier weiss ich nicht genau was du machst?

    Er erzeugt einen Enumerator. Ein Enumerator ist dazu gedacht, alle Objekte einer Collection wie NSArray, NSDictionary oder NSet zu durchlaufen.

    Original von donadm
    NSString *line;
    //Hier definirst du die "line" als String

    Er deklariert die Variable line als Pointer auf ein NSString-Objekt.

    Original von donadm
    while((line=[e nextObject]))
    //Hier komm ich auch nicht ganz mit, "line" ist wohl der String, aber da "e" versteh ich nicht, den Typ NSEnumerator kenn ich nicht?Die Schleicfe stoppt wenn es kein "nextObject" mehr gibt?

    Wie oben gesagt, dient hier der Enumerator e zum Durchlaufen aller Objekte im Array lines. Mit der Methode -nextObject gibt der Enumerator e nacheinander jedes Objekt aus lines zurück. line bekommt also nacheinander alle Zeilen aus dem String s zugewiesen. Wenn alle Objekte durchlaufen sind, gibt -nextObject nil zurück und die Schleife bricht ab.

    Original von donadm
    {
    NSArray *components=[line componentsSeparatedByString:@","];
    //mit componentsSeparatedByString separierst du sie durch nach ","

    Stimmt. Nun liegen die einzelnen Teile einer Zeile im Array components zur weiteren Verwendung bereit.

    Original von donadm
    Ich denke mir, manchmal erspart es sich etwas "rumprobieren" wenn man genauer versteht was gemeint ist und wie es funktioniert.

    Hast Du Dir auch mal die Dokumentation (in Xcode einfach mal die Alt-Taste gedrückt halten und einen Doppelklick auf einen Klassen- oder Methodennamen machen) zu den hier verwendeten Klassen und Methoden angeschaut? Das hilft auch viel beim Verstehen. ;)

    Michael
  • Hallo Michael,

    Danke! Vorab für die geduldige Ausarbeitung. Ich hab das ganze jetzt in die int main gepackt.
    Und das schaut so aus:


    int main(int argc, char *argv[])
    {
    NSString *appPath =[NSFileManager currentDirectoryPath];
    NSString *s=[NSString stringWithContentsOfFile:@"/Users/don/Documents/COCOA/LearningCocoa/Text Einlesen/bsc2000.txt"];
    NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    NSEnumerator *e=[lines objectEnumerator];
    NSString *line;

    while((line=[e nextObject]))
    {
    NSArray *components=[line componentsSeparatedByString:@","];
    // componentns verarbeiten...
    }
    return NSApplicationMain(argc, (const char **) argv);
    }


    die braune Zeile funktioniert leider nicht, es gibt dort eine Fehlermeldung:"NSFileManager not corespond to currentFileDirectoryPath" Aber was hab ich da falsch gemacht? Ich versuche ja die Methode in den eckigen Klammern aufzurufen, da sie einen String wiedergibt, der den relativen Pfad enthalten soll, damit ich ihn dann bei "stringWithContentsOfFile" angeben kann?

    gruß Don
  • Original von Michael
    Original von donadm
    NSEnumerator *e=[lines objectEnumerator];
    //Hier weiss ich nicht genau was du machst?

    Er erzeugt einen Enumerator. Ein Enumerator ist dazu gedacht, alle Objekte einer Collection wie NSArray, NSDictionary oder NSet zu durchlaufen.
    Michael

    Inwiefern ist das mit einem Enumerator performanter als mit -objectAtIndex: in einer For-Schleife durchzulaufen?

    Manfred
  • Original von asrael
    Inwiefern ist das mit einem Enumerator performanter als mit -objectAtIndex: in einer For-Schleife durchzulaufen?
    Wenn man die Länge des Arrays außerhalb der Schleife und nicht in der Bedingung (for(i=0; i<[array count]; i++) bestimmt ist die Schleife wahrscheinlich performanter. Man müßte mal in den Source-Code von Core Foundation (ist Open Source als Teil von Darwin) schauen wie dort -nextObject realisiert ist.

    -- hns
  • Original von donadm
    die braune Zeile funktioniert leider nicht, es gibt dort eine Fehlermeldung:"NSFileManager not corespond to currentFileDirectoryPath" Aber was hab ich da falsch gemacht?

    Sven hat ja schon geschrieben, was da verkehrt ist. Ergänzend eine kurze Erklärung. Es gibt in Objective-C zwei verschiedene Arten von Methoden: Klassenmethoden und Instanzmethoden. Klassenmethoden haben vorne ein '+' und Instanzmethoden haben ein '-'.
    -currentDirectoryPath ist eine Instanzmethode. Die kannst Du also nicht für das Klassenobjekt NSFileManager verwenden. Du musst also erst einmal eine Instanz von NSFileManager haben, die Du einfach mit der Klassenmethode +defaultManager bekommst.

    Michael
  • Original von asrael
    Inwiefern ist das mit einem Enumerator performanter als mit -objectAtIndex: in einer For-Schleife durchzulaufen?

    Ob ein Enumerator performanter ist als eine for-Schleife, weiß ich nicht. Ein NSArray kannst Du natürlich auch mit einer for-Schleife durchlaufen, aber bei NSDictionary oder NSSet wird's damit schwierig. Ein Enumerator kann auch bei einem Array sehr nützlich sein. Zum Beispiel kannst Du eine Methode schreiben, die auf alle Objekte in einer beliebigen Collection eine Aktion durchführt, einfach in dem Du als Parameter einen Enumerator nimmst.

    Michael
  • Hallo alle,

    ich hab's jetzt so:

    #import <Cocoa/Cocoa.h>
    int main(int argc, char *argv[])
    {

    NSString *appPath =[[NSFileManager defaultManager] currentDirectoryPath];
    NSString *s=[NSString stringWithContentsOfFile:[appPath stringByAppendingString:@"/bsc2000.txt"]];

    NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    NSEnumerator *e=[lines objectEnumerator];
    NSString *line;

    while((line=[e nextObject]))
    {
    NSArray *components=[line componentsSeparatedByString:@","];
    // componentns verarbeiten...
    printf("@%",[components objectAtIndex:0]);
    }


    return NSApplicationMain(argc, (const char **) argv);
    }


    dabei bekomme ich noch diese Fehlermeldung:
    ...
    NSCFString autoreleased with no pool in place - just leaking
    2005-07-31 11:26:01.303 Text Einlesen[11883] *** _NSAutoreleaseNoPool(): Object 0x11eb980 of class NSCFArray autoreleased with no pool in place - just leaking


    bei mir im Debugger sieht's so aus:


    argc,argv sind die zwei in main,
    appPath ist der Pfad als NSString,s ist der gesammte Text(Unicode?),
    in lines sind nun 9097 Objekte=Zeilen=wie Datensätze drinn(NSArray)
    und in components sind 3 Objecte drinn.(das rote zeigt wohl das er da grad ist?)
    Das einlesen dieser "nur" 9097 Werte dauert doch schon 2-3sec oder so auf meinem 1.33Mhz G4 iBook?
    Oder ist es nur weil er die Fehlermeldung s.o fortlaufend für jedes Objekt schreibt, was natürlich Zeit kostet?
    Die Frage ist, ich wollte im grunde eigentlich nur einen einfaches Variablen Array erstellen, wo ich auf die einzelnen Werte zugreifen kann?Also zB der 2te Wert der 45 Zeile hätte dann den Wert (als double) var(2,45)=102.45, damit ich mit dem Wert rechnen kann.
    Ich stell mir gerade die Frage ob das NSArray (da es ja anscheinend Objekte erzeugt bzw alloziert)
    das richtige ist, da es evtl. zu viel Speicher braucht und nicht notwendig ist?



    gruß Don

  • Quellcode

    1. return NSApplicationMain(argc, (const char **) argv);



    so wie das aussieht ist das ganze was du dort in deine main geschreiben hast etwas verloren?
    laut dem return würde ich denken du hast eine project für eine "normale" GUI geführte Cocoa Applikation erstellt... im normalfall machst du in der main dann garnichts sondern erzeugst alle deinen code in eigenen classen....

    was für einen project typ hast du denn erzeugt?

    sollte man das nicht vllt doch besser alles in eine entsprechende classe packen oder vllt direkt ein project für eine CLI tool erstellen?

    chartus
    snafu
    :() { :|: &};:
    sometimes i dream in hex
    Obey gravity! Because its a law!
  • pack um das ganze einmal einen AutoreleasePool drumherum.

    code:

    NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
    .
    .
    [pool release];


    Soweit ich weiß ist das bei Foundation Tools ( ist doch ohne GUI ) und bei Threads Pflicht.

    Sven

    Ich musste eigentlich nur das NSApplicationMain wieder nach oben setzen(grün)

    #import <Cocoa/Cocoa.h>
    int main(int argc, char *argv[])
    {
    return NSApplicationMain(argc, (const char **) argv);
    NSString *appPath =[[NSFileManager defaultManager] currentDirectoryPath];
    NSString *s=[NSString stringWithContentsOfFile:[appPath stringByAppendingString:@"/bsc2000.txt"]];
    NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    NSEnumerator *e=[lines objectEnumerator];
    NSString *line;
    while((line=[e nextObject]))
    {
    NSArray *components=[line componentsSeparatedByString:@","];
    // componentns verarbeiten...
    //printf("@%",[components objectAtIndex:0]);
    }
    }

    was für einen project typ hast du denn erzeugt?

    Ein normales Project bzw "Cocoa-Application". das Ganze steht in der "main.m" drinn.

    @Stalkingwolf, deine Seite gefällt mir ganz gut, hab mir das cocoThumbX mal gesaugt und ausprobiert.Sehr praktisch !


    *einzig zu bemängeln velleicht der FileBrowser der etwas noch oben reingequetscht wirkt.
    Mach vielleicht ne 3er Auftreilung, links Atrribute des Bilds, mitte die Vorschau, rechts FileBrowser oder so!?
    Aber ansonsten funkzt!

    gruß
    Don
  • Hallo Michael,

    dass kann ich wirklich nicht mir Sicherheit sagen ob noch etwas vom Code ausgeführt wird?? Wie könnte man das checken?? Naja ich mach mich morgen nochmal dran danke erstmal...


    gruß Don