2012-01-19 2 views
12

내 앱이 UTF-8 형식의 파일을 다운로드합니다. 파일 크기가 너무 커서 NSString initWithContentsOfFile 메서드를 사용하여 읽을 수 없습니다. 내가 가지고있는 문제는 NSFileHandle readDataOfLength 메서드가 지정된 바이트 수를 읽음으로써 UTF-8 문자의 일부만 읽게 될 수도 있다는 것입니다. 가장 좋은 해결책은 무엇입니까? iPhone에서 큰 UTF-8 파일을 읽으려면 어떻게해야합니까?

LATER

:

그것이 다음과 같은 코드가 작동하는지 배의 로그에 기록하자

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

내 주요 문제는 인코딩이 아닌 파일을 읽는 작업과 관련 사실이었다.

  • 이 다음은 UTF-8 문자
  • 을하지 않을 경우 분할되는 경우 마지막 바이트 (들)을 결정하기 위해 검사 -

  • +0

    이 파일의 크기는 얼마입니까? 메가 바이트? 기가 바이트? –

    +0

    파일의 크기가 5MB인데 실제로는 문제가 있음을 알 수 없습니다. –

    답변

    13

    당신은 t으로 NSData +dataWithContentsOfFile:options:error:을 사용할 수 있습니다 다음 다음 청크를 읽을 -,

  • 예 경우 다음 청크를 읽을 다음 바이트를 얻고 수정 그는 NSDataReadingMappedIfSafe 옵션을 사용하여 파일을로드하는 대신 메모리에 매핑 할 수 있습니다. 따라서 iOS의 가상 메모리 관리자를 사용하여 데스크톱 OS가 디스크상의 가상 메모리 파일을 처리하는 것과 같은 방식으로 파일의 비트가 RAM 내부 및 외부로 스왑되도록 보장합니다. 따라서 전체 파일을 한 번에 메모리에 보관할만큼 충분한 RAM이 필요하지 않은 경우 파일을 프로세서의 주소 공간 (즉, 기가 바이트)에 맞출 정도로 작게 만하면됩니다. NSData과 똑같이 작동하는 객체를 얻게되어 NSFileHandle을 사용하고 수동으로 스트리밍하는 것과 관련된 대부분의 번거 로움을 덜어줍니다.

    그렇다면 현실적으로 UTF-8을 다른 형식으로 변환 할 것을 기대할 수 있으므로 부분을 NSString으로 변환해야합니다 (그렇지 않을 수도 있지만, -initWithData:encoding:을 사용하고 NSString이 충분히 똑똑한 지 확인하는 것이 좋습니다.) 원래 데이터에 대한 참조를 유지하고 필요에 따라 UTF-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'은 0이됩니다. – jimwan

    2

    한 가지 방법은

    1. 이 특정 시점까지 읽을 수있는 것 -
    0

    utf8은 자동으로 동기화됩니다. 필요에 따라 조금만 읽은 다음 바이트 값을 읽어 코드 포인트의 경계를 결정하십시오.

    또한 fopen을 사용할 수 있으며 스택에 작고 관리 가능한 버퍼를 사용하면 메모리가 문제가되지 않습니다.

    3

    실제로 멀티 바이트 문자를 UTF-8로 분할했는지 쉽게 알 수 있습니다.연속 문자는 모두 다음과 같이 설정된 두 개의 최상위 비트를 갖습니다 : 10xxxxxx. 따라서 버퍼의 마지막 옥텟에 해당 패턴이 있으면 역순으로 스캔하여 해당 형식이없는 옥텟을 찾습니다. 이것은 문자의 첫 번째 옥텟입니다. 옥텟에서 가장 중요한 0의 위치는 문자

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

    등 6 개 옥텟까지에 얼마나 많은 옥텟을 알려줍니다.

    그래서 문자 경계를 읽기 위해 추가로 8 진수를 읽는 것이 얼마나 쉬운 지 알 수 있습니다.

    +0

    실제로 최대 네 개의 옥텟이 있지만 큰 차이는 없습니다. 끝 부분에 불완전한 UTF-8 문자가 포함 된 유효한 UTF-8 시퀀스의 시작이라고 생각되는 바이트 시퀀스가있는 경우 끝에 0x80에서 0xbf까지의 값으로 3 바이트까지 건너 뛴 다음 건너 뜁니다 값이> 0xc0 인 기껏해야 1 바이트. 선물. – gnasher729

    관련 문제