2012-01-19 16 views
12

Uygulamam, NSString initWithContentsOfFile yöntemini kullanarak okumak için çok büyük olan UTF-8 biçiminde bir dosya indiriyor. Sahip olduğum sorun, NSFileHandle readDataOfLength yönteminin belirtilen sayıda bayt okuması ve sadece bir UTF-8 karakterinin bir bölümünü okuması olabilir. Burada en iyi çözüm nedir? iPhone'da büyük bir UTF-8 dosyasını nasıl okuyabilirim?

SONRA

:

aşağıdaki kod çalıştığını jurnallerine kaydedilecektir edelim:

NSData *buf = [NSData dataWithContentsOfFile:path 
             options:NSDataReadingMappedIfSafe 
             error:nil]; 

NSString *data = [[[NSString alloc] 
        initWithBytesNoCopy:(void *)buf.bytes 
        length:buf.length 
        encoding:NSUTF8StringEncoding 
        freeWhenDone:NO] autorelease]; 

Benim asıl sorun kodlama değil, dosyayı okuma görevi ile ilgisi aslında.

  • o zaman UTF-8 karakter
  • değilse bölme ise son byte (ler) belirlemek üzere incelemek -

  • +0

    Bu dosya ne kadar büyük? Megabayt? Gigabaytlar? –

    +0

    Dosyanın büyüklüğünün 5 MB olduğunu söylesem de, bunun gerçekten önemli olduğunu göremiyorum. –

    cevap

    13

    Sen t ile NSData +dataWithContentsOfFile:options:error: kullanabilirsiniz ardından sonraki yığın okuma -

  • evet ise bir sonraki öbek okumak sonraki byte almak ve düzeltmek Dosyayı yüklemek yerine belleğe eşlemek için NSDataReadingMappedIfSafe seçeneği. Böylece, sanal disk yöneticisini, dosya bitlerinin, bir masaüstü işletim sistemi disk üzerindeki sanal bellek dosyasını işleyiş biçiminde olduğu gibi RAM'in içine ve dışına kaydırıldığından emin olmak için kullanacaktır. Bu nedenle, tüm dosyayı bir kerede bellekte tutmak için yeterli RAM'e ihtiyacınız yoktur, sadece dosyanın işlemcinin adres alanına sığacak kadar küçük olması gerekir (yani gigabaytlar). Bir NSFileHandle kullanarak ve elle akış ile ilgili zorlukların çoğunu kurtarmanız gereken normal bir NSData gibi davranan bir nesne alırsınız.

    Muhtemelen o zaman gerçekçi olduğunu gerçi o olmayabilir (başka bir biçime UTF-8 den dönüştürmek için bekleyebilirsiniz beri NSString için kısımlarını dönüştürmek gerekir

    ; NSString yeterince akıllı olup olmadığını bir -initWithData:encoding: ile gitmek zorunda ve görülmeye değer sadece orijinal verilere bir referans tutmak ve talep üzerine UTF-8'den genişlemek için), ki bu sizin sorunuzun gerçekten ne olduğunu düşündürüyor.

    -initWithBytes:length:encoding: kullanıp, makul bir bayt sayısını bir dizeye dönüştürmenizi öneririm. Daha sonra, gerçekte ne kadar çok sayıda bayt algıladığını ve okuma işaretçinizi uygun şekilde ilerletmek için -lengthOfBytesUsingEncoding:'u kullanabilirsiniz. NSString'un sağladığınız baytların sonunda herhangi bir parça karakterini atmayacağı güvenli bir varsayımdır.

    DÜZENLEME: böylece, gibi bir şey: Tabii

    // map the file, rather than loading it 
    NSData *data = [NSData dataWithContentsOfFile:...whatever... 
             options:NSDataReadingMappedIfSafe 
             error:&youdDoSomethingSafeHere]; 
    
    // we'll maintain a read pointer to our current location in the data 
    NSUinteger readPointer = 0; 
    
    // continue while data remains 
    while(readPointer < [data length]) 
    { 
        // work out how many bytes are remaining 
        NSUInteger distanceToEndOfData = [data length] - readPointer; 
    
        // grab at most 16kb of them, being careful not to read too many 
        NSString *newPortion = 
         [[NSString alloc] initWithBytes:(uint8_t *)[data bytes] + readPointer 
           length:distanceToEndOfData > 16384 ? 16384 : distanceToEndOfData 
           encoding:NSUTF8StringEncoding]; 
    
        // do whatever we want with the string 
        [self doSomethingWithFragment:newPortion]; 
    
        // advance our read pointer by the number of bytes actually read, and 
        // clean up 
        readPointer += [newPortion lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 
        [newPortion release]; 
    } 
    

    , örtük bir varsayım tüm UTF-8 kodlamaları mutlak kesin söyleyecek kadar bilgili olmak değil itiraf etmeliyim ki, benzersiz olmasıdır.

  • +0

    bu sadece metin dosyasını okuyabilir, aksi takdirde 'newPortion' sıfır olur – jimwan

    2

    Bir yaklaşım

    1. belli bir noktaya kadar okumak olurdu -
    0

    utf8 kendini senkronize eder - sadece biraz daha fazla veya daha az okuyun, ardından herhangi bir kod noktasının sınırlarını belirlemek için bayt değerlerini okuyun.

    Ayrıca fopen'u kullanabilir ve bunun için yığın üzerinde küçük, yönetilebilir bir arabellek kullanabilirsiniz ve bellek bir sorun olmayacaktır.

    3

    UTF-8'de çok baytlı karakterleri ayırıp ayırmadığınızı söylemek gerçekten çok kolay.Devam karakterlerinin tümü şu şekilde ayarlanmış en önemli iki bite sahiptir: 10xxxxxx. Bu nedenle, tamponun son sekizli o desene sahipse, o forma sahip olmayan bir sekizli bulmak için geriye doğru tarayın. Bu, karakterin ilk sekizlisi. sekizlideki en önemli 0 pozisyonu karakteri

    0xxxxxxx => 1 octet (ASCII) 
    110xxxxx => 2 octets 
    1110xxxx => 3 octets 
    

    vb 6 sekizli kadar kaç octets söyler.

    Karakter sınırına ulaşmak için kaç tane fazla oktet okuması gerektiğini anlamak oldukça basit.

    +0

    Aslında dört oktet'e kadar, ama çok fazla farketmez. Sonunda, muhtemelen bir tamamlanmamış UTF-8 karakteriyle geçerli bir UTF-8 dizisinin başlangıcı olduğunu düşündüğünüz bir bayt dizisi varsa, en fazla 0x80 ile 0xbf arasında bir değere sahip üç bayta kadar atlayın, sonra atlayın. en fazla bir bayt değerinde> = 0xc0. mevcut. – gnasher729

    İlgili konular