Großen String partiell einlesen

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

  • Großen String partiell einlesen

    Hallo zusammen,

    ich möchte grosse String-Files (>>10 MB) partiell einlesen, sprich einen gewissen Bereich einlesen, ohne den Speicher mehr als nötig zu belasten. Bisher nutze ich [NSString stringWithContentsOfFile], allerdings wird dann das komplette File in den RAM geladen. Gibt es einen Umweg, um einen Speichercrash zu verhindern?

    Gruss
  • Bevor es Objective-C gab, gab's doch dieses... wie hieß es nur... achja, habs: C ;)

    Quellcode

    1. FILE *f = fopen([fileName cStringUsingEncoding:NSUTF8StringEncoding], "r");
    2. fseek(f, 0, SEEK_END);
    3. long length = ftell(f); // gesamte Datei
    4. void *buffer = malloc(length);
    5. fread(buffer, 1, length, f); // alternativ mit fseek positionieren und irgendwas < length lesen
    6. fclose(f);
    7. NSString *content = [[NSString alloc] initWithBytesNoCopy:buffer length:length encoding:NSUTF8StringEncoding freeWhenDone:YES];


    Viele Grüße,
    Thomas
  • Oder Du kannst Die Datei in ein NSData-Objekt per -initWithContentsOfMappedFile: packen, das lädt die Datei nicht in den RAM, sondern mappt sie nur. Von dort aus kannst Du per -subDataWithRange: Teile rausschneiden und die dann z.B. per -initWithBytes:length:encoding: (NSString) in einen String lesen. Falls Dein Encoding Multibyte-Characters hat, kann es allerdings sein, dass du die in der Mitte zerschneidest.
    Multigrad - 360°-Produktfotografie für den Mac
  • mattik schrieb:

    Falls Dein Encoding Multibyte-Characters hat, kann es allerdings sein, dass du die in der Mitte zerschneidest.

    @nonsense: Das ist natürlich besonders übel, wenn es zufällig das erste Zeichen im Block ist. Das generelle Problem lässt sich entweder durch Zeichensätze mit festen Zeichenlängen (z. B. ISO-8859-1/ISO-8859-15 (= 1 Byte), UTF-16 (= 2 Byte) oder UTF-32 (= 4 Byte)) vermeiden. In West-Europa reicht in der Regel ISO-8859-15 vollkommen aus.

    Bei UTF-8 kannst Du die Datei zuerst die Blockgrenzen durch einen Scan der gesamten Datei ermitteln. Dabei musst Du nur feststellen, ob sich vor der gewünschten Blockgrenze die Einleitungsbytes für Zwei- oder Drei-Byte-Sequenzen befinden und den Block dann entsprechend verlängern bzw. verkürzen. Da kommst Du also um eine komplexe Lösung nicht drumherum. Wenn Du die Datei aber nur Scannen möchtest, sollte sich der Aufwand in Grenzen halten.
    „Meine Komplikation hatte eine Komplikation.“
  • mattik schrieb:

    Oder Du kannst Die Datei in ein NSData-Objekt per -initWithContentsOfMappedFile: packen, das lädt die Datei nicht in den RAM, sondern mappt sie nur. Von dort aus kannst Du per -subDataWithRange: Teile rausschneiden und die dann z.B. per -initWithBytes:length:encoding: (NSString) in einen String lesen. Falls Dein Encoding Multibyte-Characters hat, kann es allerdings sein, dass du die in der Mitte zerschneidest.

    –rangeOfComposedCharacterSequenceAtIndex:

    Einfach auf length-8 anwenden und den Rest wegwerfen. Sollte eigentlich das Problem lösen. (8 meine ich deshalb, weil ich im Kopp habe, dass maximal 4 Zeichen komponiert sein können und es sich ja um Zeichen aus der Unicode_Extension handeln könnte, die in Cocoa als zwei Zeichen geschrieben werden. Mutmaßlich reicht aber auch 4, da ich meine, dass in der Extension keine Composings vorkommen. Aber sicher ist sicher.)
    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"?
  • Hallo,

    via mappedData scheint es zu klappen. Vielen Dank nochmals für eure kompetente Hilfe.

    Quellcode

    1. NSData* mappedData = [NSData dataWithContentsOfMappedFile:path];
    2. NSRange maxRange;
    3. maxRange.location = 0;
    4. maxRange.length = fileSizeLimit * 1024 * 1024;
    5. sessionData = [mappedData subdataWithRange:maxRange];
    6. NSString* sessionDataString = [[[NSString alloc] initWithData:sessionData encoding:4] autorelease];