ASCII Dateien einlesen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • ASCII Dateien einlesen

    Hallo Gemeinde,

    Ich hab auch mal wieder vor, etwas mit Cocoa bzw. Objective C zu machen.
    Und komme darauf zurück, was ich schon immer auf Apple-Basis mal realisieren wollte.

    Ich wollte gerne eine Sternkarte plotten.

    Dabei geht es darum, die Daten der Sterne, sprich Positionsangaben,
    Helligkeit ect. aus ASCII Dateien auszulesen ?!

    Es gibt ein grosses Achiv, von sehr grossen Katalogen,
    mit teilweise meherern Millionen Datensätze an Sterndaten.

    Als Beispiel,
    habe ich mal den PPM Katalog ausgewählt, der Link dazu
    cdsweb.u-strasbg.fr/viz-bin/ftp-index?I/208
    hier kann man sich den Katalog runterladen Datei "ppm3.dat.gz".

    Wenn ich diese Datei nun geladen hab, kann ich sie mit Textedit öffenen
    und was dort erscheint, ist das:
    [Blockierte Grafik: http://www.dwienand.de/Expo/ppm.png]
    hier sind nun die einzelnen Datensätze schön der Reihe nach angeordnet.
    Nun möchte ich aber dezidiert auf bestimmte Daten zugreifen und dazu gibt es zu jedem
    Katalog einen Readme die etwa so aussieht:

    File Summary:
    ------------------------------------------------------------------------
    FileName Lrecl Records Explanations
    ------------------------------------------------------------------------
    ReadMe 80 . This file
    ppm3.dat 131 89676 The catalogue
    desc.txt 78 261 Authors' description
    ------------------------------------------------------------------------

    Byte-per-byte Description of file: ppm3.dat
    ------------------------------------------------------------------------
    Bytes Format Units Label Explanations
    ------------------------------------------------------------------------
    2- 7 I6 --- PPM *[700001/789676]+ Designation of the star
    10-18 A9 --- DM *Durchmusterung, BD or CD
    20-23 F4.1 mag Mag *Magnitude, Visual if Flag5 is 'V'
    25-26 A2 --- Sp *Spectral type
    28-29 I2 h RAh Right Ascension for the Equinox=J2000.0 5
    31-32 I2 min RAm Right Ascension J2000 (minutes)
    34-39 F6.3 s RAs Right Ascension J2000 (seconds)
    42 A1 --- DE- Declination J2000 (sign)
    43-44 I2 deg DEd Declination for the equinox and epoch
    ...


    hier stehen Byte-Bereiche, was für welche Daten reserviert ist.

    Meine Fragen jetzt dazu:
    * Wie kann ich es möglichst einfach Lösen, die Daten einzulesen, um sie weiter in meinem
    Programm zu benutzen? Ich hatt mir gedacht, das ich einen "Importer" oder ähnliches dafür
    baue, der dann das Lesen der Daten aufgrund der Byte-Angaben übernimmt ?

    * Da es hier um grosse Datenmengen geht (die zusäzlich zur Laufzeit des Programms "fliessen"
    müssen), müsste ich mir Strategien zur Verarbeitung überlegen? Evtl. könnte man das Ganze
    in eine Datenbank importieren, doch hier sehe ich die Gefahr, das das "Lesen" zu langsam geht?

    Ich will euch jetzt nicht fragen, wie das "technisch" genau vor sich geht, mir gehts nur um eine
    grobe Richtung vom Denkansatz her. Also, ist es Sinnvoll da einen Importer für zu bauen?
    Welche Klassen, Objekte könnte man zur Hilfe nehmen ect.
    Es geht eigentlich nur?? darum, die Daten eben aus diesen Dateien zu lesen, sie in Variablen
    innerhalb des Programms zwischenzuspeichern, ein paar Berechnungen mit ihnen zu machen
    und sie zum Plotten von Stern-Scheibchen zu benutzen.

    Jeder Ast im fliessenden Wasser würd mir helfen :)
  • klar kannst du das ganze in eine DB packen (SQLite/CoreData eventuell). Es kommt eben drauf an wann und wie du die daten brauchst.
    wenn du zb ALLE daten auf einmal brauchst (weil du sie durchgehen musst und analysieren) und dann alle ausdrucken oder am bildschrim darstellen und das noch recht schnell gehen sollte dann lies das einfach alles ein und pack jede sterninfo in ein objekt und arbeite damit.
    wenn du immer nur wenige solcher sterninfos brauchst (zb um in einer tabelle darzustellen) dann reicht die geschwindigkeit die direkt aus der DB zu holen auch aus.

    importer wirst dir auf jeden fall schreiben müssen (was auch recht einfach geht (fopen, fread, fclose oder NSFileHandle oder NSData) - die frage ist nur ob du die importierten infos im speicher halten willst (zum schnellen zugriff) oder sie in eine db packst und nur bei bedarf drauf zugreifst (langsamer aber speicherschonender). Wie gesagt es kommt drauf an was du mit den daten machen willst!
  • Hallo gritsch,
    danke erstmal für deine schnelle Antwort.
    Ich muss erlich sagen, das ich noch "blutiger Anfänger" bin :).

    Im Grunde geht es nur darum, wie ich geschreiben hab, diese Daten einzulesen, etwas damit zu rechnen und dann auf eine Karte zu plotten/drawn.

    Versuch es dir vielleicht mal vorzustellen:
    Wenn ich zB. den Ganzen Himmel darstelle (also 360°) muss ich zwar den ganzen Katalog
    einlesen, daraus aber nur die Hellsten darstellen. Dh. ich lese 1Mill. ein und zeichne aber nur
    1000 davon auf meine ganze Karte.

    Wenn ich dann einzoome, erscheinen natürlich schwächere Sterne, dh, nun brauch ich mehr Sterne.
    Der Himmelsausschnitt verkleinert sich aber und so brauch ich wieder nur 1000-1500 Stern zeichnen.
    Es kompensiert sich also.

    Die Sache ist halt, das man schnell mit den Daten "arbeiten" muss (zB. nach Helligkeit sortieren) ect.
    Dafür wäre es schon Sinnvoll, einen Grossteil davon im Speicher zu behalten.

    Das NSData klingt dafür schon recht gut :)
    Ich hoffe das das:
    developer.apple.com/documentat…f/doc/uid/20000717-133953
    in die richtige Richtung geht
  • char buffer[7];
    [myData getBytes:&buffer range:NSMakeRange(1,6)];
    buffer[6] = 0;
    unsigned dieKomischeZahl = atoi(buffer);

    so in der art und schon hast du die erste zahl. so gehst du dann alle zahlen durch und legst dir für jede zeile (also jedes gestirn) ein Objekt an. Ich würd das erstmal so machen dasas es funktioniert (also einfach alles in den speicher laden) und erst danach den zwischenteil coden der die ganzen daten beim einlesen in eine DB packt und nachher bei gebrauch wieder rausholt.

    ob du das jetzt mit fread und co oder mit NSFileHandle oder NSData machst ist nicht weiter tragisch sondern eher nur eine sache des geschmacks (und eventuell des speicherverbrauchs ;-))
  • so, ich hab noch eine älteres Projekt gefunden, wo ich mit dem Einlesen eines Katalogs mal angefangen hatte.

    Der Katalog sieht von der Struktur so aus:

    101.28708 , -16.71611 , -1.46
    95.98792 , -52.69583 , -0.72
    213.91542 , 19.1825 , -0.04
    219.89958 , -60.83528 , -0.01
    279.23458 , 38.78361 , 0.03
    79.1725 , 45.99806 , 0.08
    78.63458 , -8.20167 , 0.12
    114.82542 , 5.225 , 0.38


    Mein code in der "main.h" sieht so aus:

    Quellcode

    1. #import <Cocoa/Cocoa.h>
    2. int main(int argc, char *argv[])
    3. {
    4. NSString *appPath =[[NSFileManager defaultManager] currentDirectoryPath];
    5. NSString *s=[NSString stringWithContentsOfFile:[appPath stringByAppendingString:@"/bsc2000.txt"]];
    6. NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    7. NSEnumerator *e=[lines objectEnumerator];
    8. NSString *line;
    9. while((line=[e nextObject]))
    10. {
    11. NSArray *components=[line componentsSeparatedByString:@","];
    12. // componentns verarbeiten...
    13. }
    14. }
    Alles anzeigen


    Wenn ich das Ganze mit Apfel+R kompiliere
    bekomme ich das:

    Quellcode

    1. [Session started at 2007-02-03 17:03:22 +0100.]
    2. 2007-02-03 17:03:23.258 Text Einlesen[12013] *** _NSAutoreleaseNoPool(): Object 0x303d30 of class NSCFString autoreleased with no pool in place - just leaking
    3. 2007-02-03 17:03:23.260 Text Einlesen[12013] *** _NSAutoreleaseNoPool(): Object 0x308140 of class NSCFString autoreleased with no pool in place - just leaking
    4. 2007-02-03 17:03:23.260 Text Einlesen[12013] *** _NSAutoreleaseNoPool(): Object 0x308320 of class NSCFString autoreleased with no pool in place - just leaking
    5. 2007-02-03 17:03:23.263 Text Einlesen[12013] *** _NSAutoreleaseNoPool(): Object 0x29c000 of class NSCFString autoreleased with no pool in place - just leaking
    6. 2007-02-03 17:03:23.264 Text Einlesen[12013] *** _NSAutoreleaseNoPool(): Object 0x3085f0 of class NSCFArray


    Also das heisst, die Klasse NSCFString hat irgendwo ein "autorelease" mit keinem "pool in place" und leckt?
    Und was bedeutet das 0x303d30 zB? ist das die Kennung meines Objekts?

    Sinnvoll wäre es einfach mal, die Daten von oben, zB erste Zeile:
    101.28708 , -16.71611 , -1.46
    in ein DataGrid oder Liste zu laden, das man sie hat und damit weiter arbeiten kann.

    Und ich muss natürlich sagen, Objektive C ist für mich Absolute Neuland und ich fange erst an, es zu lernen:)
  • Lies in der Wiki mal den Artikel zur Speicherverwaltung. Das Problem hier löst du indem du am Anfang von main() schreibst:

    Quellcode

    1. NSAutoreleasePool *ARP = [[NSAutoreleasePool alloc] init];"


    Hast du schon ein Buch zu Cocoa?
    "Wales is the land of my fathers. And my fathers can have it." - Dylan Thomas
  • hallo laeng,
    ich hab ein Buch mal bis 3/4 durchgearbeitet, da ging es um mutable Strings NSString class, umd die Adressbuch klasse usw. ein bisschen um den interface builder und wie man einen Spot mit einem Slider die Grösse ändern konnte ect. Etwas über subclass ect. ging es meine ich auch.
    Das Ganze ist allerdings etwas her und ich hab das Meiste nicht mehr im Kopf.

    Allgemein muss ich erstmal wieder reinkommen.
    Falls du einen Tip für ein online Tutorial oder persönliche Tips hast, lass es mich wissen.
  • ok, ich weiss nicht wo es hinpasst aber ich fang vll mal ganz von vorne an.
    Ich hab viel in Actionscript programmiert und habe da ziemlich viele Variablen benutzt also
    zB.

    Quellcode

    1. var meineString:String = "Hello";
    2. var meineZahl:Number = 12345;
    3. var meinObj:Object = new Object;


    Doch ich hab das Gefühl, das man in Objective C gar nicht mehr so Variablen benutzt sonder eher Objeke ? Was für mich einen neue, aber auch Spannende erfahrung ist.
    Um zB. einen Variable(Objekt?) vom Typ Nummer zu Definieren macht ich das so?

    Quellcode

    1. NSNumber *meineNummer = [[NSNumber alloc] init];

    Wobei ich jetzt nicht vestehe ob das ein Objekt oder nur eine Variable ist?
    "meine Nummer" vom Typ/Klasse NSNumber istgleich NSNumber alloc(allocate=Speicher zuweisen ) und init(=initalize=in den Speicher packen)

    In der Wikepedia hab ich folgenden Code gefunden und versuche ihn auch mal(soweit ich kann und weiss) zu erklären:

    Quellcode

    1. // meineWelt wird aus der Klasse NSMutableDictionary erstellt, zugewiesen und initalisiert
    2. NSMutableDictionary *meineWelt = [[NSMutableDictionary alloc] init];
    3. // Eine Map mit einem String, einer URL und einem Wert
    4. // setObject ist eine Methode von NSMutableDictionary und es wird "Ein Text" mit Schlüsse "Text" vergeben
    5. [meineWelt setObject:@"Ein Text" forKey:@"Text"];
    6. [meineWelt setObject:[NSURL URLWithString:@"www.example.com"] forKey:@"URL"];
    7. [meineWelt setObject:[NSNumber numberWithInt:3] forKey:@"Zahl"];
    8. // Alle Objekte implementiern die Methode description
    9. NSLog( @"%@", [[meineWelt objectForKey:@"Text"] description] );
    10. NSLog( @"%@", [[meineWelt objectForKey:@"URL"] description] );
    11. NSLog( @"%@", [[meineWelt objectForKey:@"Zahl"] description] );
    12. //hier wird das Objekt wieder aus dem Speicher geräumt
    13. [meineWelt release];
    Alles anzeigen

    Bei NSLog verstehe ich nicht das @"%@", das "description" wird wohl eine Methode sein, eben die Schlüssel im Fenster auszugeben.

    uff uff, das ist einiges und wie ihr seht, hab ich damit noch gute Probleme. Objective >C ist warscheinlich die Schwerste Sprache, die ich je gelernt hab.
    In Javascript oder Actionscript sagt man doch einfach:
    var a=12;
    was ist denn der Parntant dazu in Objective C ?
    NSNumber *a = [[NSNumber alloc] init];
    a=12;
  • Also, deine Variable "meineNummer" ist ein Zeiger/Pointer (wird durch das * ausgedrückt) auf ein Objekt. Das Objekt liegt irgendwo im Speicher.
    Mittels

    Quellcode

    1. NSNumber *meineNummer = [[NSNumber alloc] initWithInt:5];

    werden 2 Methoden ausgeführt:
    Die erste Methode ist eine Klassen-Methode: [NSNumber alloc] schickt an die Klasse NSNumber den Befehl, Speicher für eine NSNumber-Instanz anzulegen. Der Rückgabewert ist dann ein Objekt.
    Die zweite Methode ist eine Instanz-Methode: Dem mittels alloc erstellten Objekt (=Instanz) soll dann mittels "initWithInt" ein Wert zugewiesen werden. Der Rückgabewert dieser Methode ist das selbe Objekt, es hat nun allerdings eine Nummer eingespeichert. Dem Pointer "meineNummer" weist du nun die Speicheradresse von diesem Objekt zu, so dass du es noch in Zukunft ansprechen kannst.

    Du hättest diese beiden Methoden auch getrennt aufrufen können:

    Quellcode

    1. NSNumber *meineNummer = [NSNumber alloc]; // Erstelle Instanz von NSNumber
    2. [meineNummer initWithInt:5]; // Weise dem soeben erstelltem Objekt eine Nummer zu



    Ich weiß nun allerdings nicht, was du mit einer NSNumber Instanz anfangen willst. Willst du damit rechnen, so solltest du dir die elementaren Datentypen von C anschauen. Willst du diese Werte speichern oder so solltest du diese in einer NSNumber Instanz ablegen.

    Hoffentlich habe ich dich jetzt nicht zu sehr verwirrt.
    There are 10 kinds of people in the world - those who understand binary
    and those who don't.
  • Thx squart,
    du hast mich nicht verwirrt, eher geholfen:)

    Eine ganz wichtige frage fällt mir noch allgemein ein:

    Kann ich ernsthaft Schäden an meinem System verursachen?

    Ich bin mir nicht ganz Sicher, in wie weit ich wirklich in Systemnahe Prozesse eingreifen oder
    eben durch Benutzung des Speichers schäden anrichten kann?
    Gerade weil ich noch sehr unerfahren bin, weiss ich nicht, was passieren kann?
    Was für Erfahrungen habt ihr bzgl. XCode Stabilität und Systemsytabilität gemacht?
  • Original von gritsch
    ob du das jetzt mit fread und co oder mit NSFileHandle oder NSData machst ist nicht weiter tragisch sondern eher nur eine sache des geschmacks (und eventuell des speicherverbrauchs ;-))


    Bei NSData kann man es sogar als Mapped-File einlesen, d.h. es geht auch wenn relativ wenig Speicher frei ist.
  • Original von donadm
    Kann ich ernsthaft Schäden an meinem System verursachen?

    Ich bin mir nicht ganz Sicher, in wie weit ich wirklich in Systemnahe Prozesse eingreifen oder
    eben durch Benutzung des Speichers schäden anrichten kann?


    Tja, hier ist leider festzustellen, daß die Benutzung des Speichers Energie braucht und der Halbleiter im Laufe von Jahrhunderten ausgeleiert wird. Also wird Dein Programm auf jeden Fall irgendwelche Schäden anrichten...


    Gerade weil ich noch sehr unerfahren bin, weiss ich nicht, was passieren kann?
    Was für Erfahrungen habt ihr bzgl. XCode Stabilität und Systemsytabilität gemacht?


    Aus Cocoa heraus ist es (fast) unmöglich irgendetwas wirklich Schlimmes zu fabrizieren (einen "rm -rf /*" kann man aber trotzdem fabrizieren). MacOS X ist stabiler als das meiste andere. Xcode selbst schmiert manchmal ab (z.B. wenn man 2 Projekte gleichzeitig übersetzen läßt).

    -- hns
  • als gesagt wurde dass du dich mit C-Typen anfreunden sollst war sowas gemeint:

    long, int, unsigned, char etc.

    diese kannst du auch ganz normal verwenden wie du es von actionscrip gewöhnt bist:

    unsigned int meineZahl = 12;
    meineZahl = 34567;

    etc...

    wie immer gilt: wenn du dir die mühe sparen willst, sag mir was du brauchst und ich sag dir was es kostet ;)
  • hallo,

    so, ich hab mir gedacht, jetzt einmal etwas konkreter zu werden und meine kleine App
    nach dem MVC (Model View Conroler) Model aufzubauen.
    Für die ersten Schritte dachte ich mir, einfach mein meine Ascii (bzw. Textdatei)
    einfach in ein NSTextView anzuzeigen bzw einzulesen.

    Wie gehe ich da jetzt vor?

    1) Ich hab die .nib Datei aufgemacht und dort ein NSTextView draufgezogen.
    Wenn ich das Projekt starte, wir aber nicht das Window geladen, obwohl die Option "Visible at lauchtime" gechecked ist?

    2) Bisher habe ich meine ganzen Code in der main-Routine von main.m

    Quellcode

    1. #import <Cocoa/Cocoa.h>
    2. int main(int argc, char *argv[])
    3. {
    4. NSAutoreleasePool *ARP = [[NSAutoreleasePool alloc] init];
    5. NSString *appPath =[[NSFileManager defaultManager] currentDirectoryPath];
    6. // /bsc2000.txt
    7. NSString *s=[NSString stringWithContentsOfFile:[appPath stringByAppendingString:@"/ppm3.dat"]];
    8. NSArray *lines=[s componentsSeparatedByString:@"\n"]; // ggf. \r\n nehmen!
    9. NSEnumerator *e=[lines objectEnumerator];
    10. NSString *line;
    11. while((line=[e nextObject]))
    12. {
    13. NSArray *components=[line componentsSeparatedByString:@","];
    14. // componentns verarbeiten...
    15. }
    16. }
    Alles anzeigen

    Wie teile ich das Ganze nun nach dem MVC Model auf ? Und wie kann ich mit dem NSTextView
    mit den Daten aus meiner while-Schleife füllen( NSString *line) ? Wie stelle ich die Verbindung da her?
    Sollte ich eine Klasse "controller.m" und evtl. "model.m" anlegen ?

    Im weiteren Verlauf wäre zu überlegen, ob ich die Daten dann in ein NSTableView einlesen kann,
    wobei sie natürlich dann schon aufgeteilt sein müssen, um sie dementsprchend in die Spalten zu
    lesen.

    Das Ganze will ich machen, um meine Daten auch zu "sehen", das sie auch da sind.
    Das Einlesen ging recht flott, doch weiss ich eben nicht, ob überhaupt was da ist?
    Die Anzeige im NSTextView oder NSTableView wird aber warscheinlich dann schon
    etwas Zeit brauchen nehem ich an.

    Bzgl. der C-Datentypen hab ich mich mal da:
    homepage.univie.ac.at/Heinz.Kabelka/edv-ueb/variabl.htm
    umgeschaut.
  • Die Aufteilung erfolgt ganz einfach: Alles was Daten sind, schreibst du ins Model. :)

    Nein, mal ernsthaft. Zunächst musst du dich fragen, was überhaupt die Daten deiner Applikation" sind. Üblicherweise hast du so genannte Entitäten, d.h. Objekt mit gewissen Eigenschaften und Beziehungen. Du machst dir eine Liste solcher Entitäten und beschreibst sie dabei. Irgendwie hast du zumeist eine oberste Entität "die Datei itself". Bei DBA sind das die Dokumente, bei non-DBA machst du dir selbst ein solches Root-Objekt. Du kannst es einfach im mainMenu.nib herstellen.

    Wenn ich mir dein Projekt so anschaue, dann hast du vor allem Entitäten vom Typ "Stern", die eine ganze Reihe von Attributen haben. Am besten machst du dir noch eine Entität vom Typ "Karte", die über ein Array auf die einzelnen Sterne verweist.

    Du kannst dir ürbigens dein Model in Core-Data schön zusamenstöüseln.

    Hast du ein solches Model, dann musst diu es mit den Text-Views verbinden. Dabei gibt es im Prinzip drei Systeme:

    a) Manuell: Ändert sich etwas im Model, so muss dies der Controller abholen und im View setzen. Das bedeutet bei größeren Applikationen viel Arbeit und ist schlecht zu warten.

    b) Data-Sources: Du implementierst ein Objekt, welches NAchrichten vom View bekommt, wenn eine Änderung notwednig ist.

    c) Bindings: Du verwendest die Standard-Bindings-Controller von Cocoa.
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • hm entweder hast du einfach ausversehen das falsche projekt templateverwendet...

    oder deine erfahrung mit xcode bzw dem entwicklen auf dem mac hält sich arg in grenzen

    dein fenster wird ua deswegen nicht geöffnet weil du die basis einer GUI geführten cocoa application garnicht startest dieses ominöse "return NSApplicationMain(argc, (const char **) argv);" welches immer in der main.m steht wenn man ein neues projekt für "Objectiv C Standard Application" erzeugt

    so wie du es jetzt hast, fehlt praktisch alles - deine umgebende Application Klasse, dein nib loader etc pp
    und wenn das nciht da ist, wird natürlich das Fenster nciht "automatisch" geladen und erzeugt
    da ich nun bezweifel das du das wirklich alles von hand machen willst solltest du nochmal in die basics schauen... zb diese bis zum erbrechen viel zitierte "Calculator tutorial" oder ähnliches
    snafu
    :() { :|: &};:
    sometimes i dream in hex
    Obey gravity! Because its a law!
  • ok well people, as far as i assume i cant be proud of myself if it comes to the point in knowing much about the xcode and cocoa enviroment, also I try to give my best in achiving some skills and i do read a lot (i can tell:)) documentation- I've done it over the hole day so.
    Nevertheless...

    mal wieder nach deutsch switchen...ähm wechseln.

    Ok, vll sollte ich erstmal mit dem Currency Converter anfangen...
    Falls ich da erstlich ins Straucheln komme, kann ich ja hier im Forum den Notanker werfen...:)

    Danke für die Tips von euch nochmal!
  • ok dann zeig ich euch mal meine ersten Schwimmversuche:

    Soweit ich das verstanden hab, geht man so vor:

    *) die main.m eigentlich in Ruhe lassen
    *) Man öffnet die .nip file, erzeugt dort 2 Klassen (von NSObject),
    eine heisst Controller, die ander Model
    *) Man setzt die Outlet/Aktion für Klasse Controler
    *) Man instanziert Conroller und auch Model
    *) Man verbindet die Outlets und Aktions mit den Elementen auf dem Window
    *) Man verbindet Controller(Instanz) und Model(Instanz)
    *) Man Man erzeugt die Dateien für Controller und Model

    Frage, arbeitet ihr auch nach dem MCV(Model-Controller-View) Paradigma?
    Oder ist das für den anfang nur recht hilfreich?