2012-01-19 8 views
12

मेरा ऐप यूटीएफ -8 प्रारूप में एक फ़ाइल डाउनलोड करता है, जो NSString initWithContentsOfFile विधि का उपयोग करके पढ़ने के लिए बहुत बड़ा है। मेरी समस्या यह है कि NSFileHandle readDataOfLength विधि बाइट्स की एक निर्दिष्ट संख्या पढ़ती है, और मैं केवल यूटीएफ -8 वर्ण का हिस्सा पढ़ सकता हूं। यहां सबसे अच्छा समाधान क्या है?मैं एक आईफोन पर एक बड़ी यूटीएफ -8 फाइल कैसे पढ़ सकता हूं?

बाद में:

चलो यह जहाज के लॉग में दर्ज किया जा है कि निम्नलिखित कोड काम करता है:

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]; 

मेरा मुख्य समस्या वास्तव में था एन्कोडिंग, नहीं फ़ाइल को पढ़ने के कार्य के साथ क्या करना है।

+0

यह फ़ाइल कितनी बड़ी है? मेगाबाइट? गीगाबाइट? –

+0

हमें बताएं कि फ़ाइल का आकार 5 एमबी है, हालांकि मैं नहीं देख सकता कि यह वास्तव में मायने रखता है। –

उत्तर

13

आप टी के साथ NSData +dataWithContentsOfFile:options:error: उपयोग कर सकते हैं तो अगले हिस्सा पढ़ा वह NSDataReadingMappedIfSafe विकल्प को लोड करने के बजाय अपनी फ़ाइल को स्मृति में मैप करने का विकल्प। ताकि आईओएस में वर्चुअल मेमोरी मैनेजर का उपयोग यह सुनिश्चित करने के लिए किया जा सके कि फाइल के बिट्स रैम में और बाहर से बदल दिए गए हैं जैसे डेस्कटॉप ओएस अपनी ऑन-डिस्क वर्चुअल मेमोरी फाइल को संभालता है। इसलिए आपको पूरी फ़ाइल को स्मृति में एक साथ रखने के लिए पर्याप्त रैम की आवश्यकता नहीं है, आपको बस प्रोसेसर के पता स्थान (इसलिए, गीगाबाइट्स) में फ़िट होने के लिए पर्याप्त छोटा होने की आवश्यकता है। आपको एक ऑब्जेक्ट मिलेगा जो सामान्य NSData की तरह कार्य करता है, जो आपको NSFileHandle का उपयोग करने और मैन्युअल रूप से स्ट्रीमिंग से संबंधित अधिकांश परेशानी को बचाएगा।

आप शायद तब NSString के कुछ भागों में परिवर्तित करने के बाद आप वास्तविक कि UTF-8 से किसी अन्य स्वरूप में परिवर्तित करने के लिए (हालांकि यह नहीं हो सकता है उम्मीद कर सकते हैं की आवश्यकता होगी, यह एक -initWithData:encoding: के साथ जाने के लिए होने और देखने लायक है, चाहे NSString बहुत चालाक है सिर्फ मूल डेटा का संदर्भ रखने और मांग पर यूटीएफ -8 से विस्तार करने के लिए), जो मुझे लगता है कि आपका प्रश्न वास्तव में क्या हो रहा है।

मेरा सुझाव है कि आप -initWithBytes:length:encoding: का उपयोग स्ट्रिंग में उचित बाइट्स को परिवर्तित करने के लिए करें। इसके बाद आप यह पता लगाने के लिए -lengthOfBytesUsingEncoding: का उपयोग कर सकते हैं कि वास्तव में कितने बाइट्स ने वास्तव में आपके पढ़ने वाले सूचक को उचित रूप से समझ लिया है और अग्रिम कर दिया है। यह एक सुरक्षित धारणा है कि NSString आपके द्वारा प्रदान किए गए बाइट्स के अंत में किसी भी भाग वर्ण को त्याग देगा।

संपादित करें: हां, तो कुछ इस तरह:

// 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]; 
} 

बेशक, एक अंतर्निहित धारणा है कि सभी को UTF-8 एनकोडिंग अद्वितीय हैं, मैं काफी जानकार निरपेक्ष कुछ के लिए कहने के लिए किया जा रहा है के लिए नहीं स्वीकार करना होगा जो है।

+0

यह केवल टेक्स्ट फ़ाइल पढ़ सकता है, अन्यथा 'newPortion' शून्य – jimwan

2

एक दृष्टिकोण होगा

  1. एक निश्चित बिंदु तक पढ़ -
  2. तो जांच अगर यह एक UTF-8 वर्ण
  3. नहीं तो बंटवारे पिछले बाइट (रों) निर्धारित करने के लिए - अगले हिस्सा पढ़ा
  4. अगर हां, अगले बाइट हो और ठीक -
0

utf8 स्वयं सिंक्रनाइज़िंग है - बस थोड़ी अधिक या कम आवश्यकतानुसार पढ़ें, फिर किसी भी कोड बिंदु के लिए सीमा निर्धारित करने के लिए बाइट मान पढ़ें।

भी, आप fopen का उपयोग कर सकते हैं और इसके लिए स्टैक पर एक छोटा, प्रबंधनीय बफर का उपयोग कर सकते हैं और स्मृति कोई समस्या नहीं होगी।

3

वास्तव में यह कहना आसान है कि आपने यूटीएफ -8 में एक मल्टीबाइट चरित्र को विभाजित किया है या नहीं।निरंतरता वर्णों में सभी की तरह दो सबसे महत्वपूर्ण बिट्स सेट हैं: 10xxxxxx। तो यदि बफर के आखिरी ऑक्टेट में वह पैटर्न है, तो उस ऑक्टेट को खोजने के लिए पीछे की ओर स्कैन करें जिसमें वह फ़ॉर्म नहीं है। यह चरित्र का पहला ऑक्टेट है। ओकटेट में सबसे महत्वपूर्ण 0 की स्थिति बताता है कि आप कितने ओक्टेट्स चरित्र

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

और इतने पर 6 ओक्टेट्स अप करने के लिए कर रहे हैं।

तो यह पता लगाने के लिए काफी छोटा है कि चरित्र सीमा तक पहुंचने के लिए कितने अतिरिक्त ऑक्टेट्स पढ़ना है।

+0

वास्तव में चार ऑक्टेट्स तक होगा, लेकिन इससे कोई फर्क नहीं पड़ता है। यदि आपके पास बाइट्स का अनुक्रम है जो आपको लगता है कि एक वैध यूटीएफ -8 अनुक्रम की शुरुआत अंत में एक अधूरा यूटीएफ -8 वर्ण है, तो अंत में 0x80 से 0xbf के मान के साथ तीन बाइट्स तक छोड़ें, फिर छोड़ें एक मूल्य के साथ एक बाइट पर> = 0xc0। वर्तमान। – gnasher729

संबंधित मुद्दे