2013-02-10 1 views
2

NSInputStream을 사용하여 iOS에서 대용량 파일을 읽으려고하면 줄 바꿈으로 파일 줄을 구분하려고합니다 (너무 많은 메모리를 사용하므로 componentsSeparatedByCharactersInSet을 사용하고 싶지 않습니다).UTF-8로 NSInputStream을 읽는 방법은 무엇입니까?

그러나 모든 행이 UTF-8로 인코딩 된 것처럼 보이지는 않습니다 (ASCII, 같은 바이트로 표시 될 수 있음). 나는 종종 Incorrect NSStringEncoding value 0x0000 detected. Assuming NSASCIIStringEncoding. Will stop this compatiblity mapping behavior in the near future. 경고를받습니다.

내 질문은 :이 경고를 예를 들어 예 : 컴파일러 플래그를 설정 하시겠습니까?

추가 : 바이트 스트림에서 읽은 다음 버퍼를 문자열로 변환 한 다음 문자열을 추가하면 문자열이 손상 될 수 있으므로 두 개의 버퍼 읽기를 추가/연결하지 않습니까?

아래의 예는 바이트 단위의 문자열 변환이 UTF-8 문자의 첫 번째와 두 번째 절반을 유효하지 않은 것으로 삭제한다는 것을 보여줍니다.

- (void)NSInputStreamTest { 
    uint8_t testString[] = {0xd0, 0x91}; // @"Б" 

    // Test 1: Read max 1 byte at a time of UTF-8 string 
    uint8_t buf1[1], buf2[1]; 
    NSString *s1, *s2, *s3; 
    NSInteger c1, c2; 
    NSInputStream *inStream = [[NSInputStream alloc] initWithData:[[NSData alloc] initWithBytes:testString length:2]]; 

    [inStream open]; 
    c1 = [inStream read:buf1 maxLength:1]; 
    s1 = [[NSString alloc] initWithBytes:buf1 length:1 encoding:NSUTF8StringEncoding]; 
    NSLog(@"Test 1: Read %d byte(s): %@", c1, s1); 
    c2 = [inStream read:buf2 maxLength:1]; 
    s2 = [[NSString alloc] initWithBytes:buf2 length:1 encoding:NSUTF8StringEncoding]; 
    NSLog(@"Test 1: Read %d byte(s): %@", c2, s2); 
    s3 = [s1 stringByAppendingString:s2]; 
    NSLog(@"Test 1: Concatenated: %@", s3); 
    [inStream close]; 

    // Test 2: Read max 2 bytes at a time of UTF-8 string 
    uint8_t buf4[2]; 
    NSString *s4; 
    NSInteger c4; 
    NSInputStream *inStream2 = [[NSInputStream alloc] initWithData:[[NSData alloc] initWithBytes:testString length:2]]; 

    [inStream2 open]; 
    c4 = [inStream2 read:buf4 maxLength:2]; 
    s4 = [[NSString alloc] initWithBytes:buf4 length:2 encoding:NSUTF8StringEncoding]; 
    NSLog(@"Test 2: Read %d byte(s): %@", c4, s4); 
    [inStream2 close]; 
} 

출력 :

2013-02-10 21:16:23.412 Test[11144:c07] Test 1: Read 1 byte(s): (null) 
2013-02-10 21:16:23.413 Test[11144:c07] Test 1: Read 1 byte(s): (null) 
2013-02-10 21:16:23.413 Test[11144:c07] Test 1: Concatenated: (null) 
2013-02-10 21:16:23.413 Test[11144:c07] Test 2: Read 2 byte(s): Б 
+0

그럼, 무엇이 당신의 질문입니까? –

+0

@ 0x7fffffff 질문을 추가했습니다. 죄송합니다. 또한 2 배가 될 수도 있습니다. – Kreisquadratur

답변

1

우선, 줄에 : s3 = [s1 stringByAppendingString:s2]; 'nil'값에 연결하려고합니다. 그 결과도 'nil'이 될 것입니다. 그래서, 당신은 문자열 대신 바이트을 연결 할 수 있습니다 :

uint8_t buf3[2]; 
buf3[0] = buf1[0]; 
buf3[1] = buf2[0]; 
s3 = [[NSString alloc] initWithBytes:buf3 length:2 encoding:NSUTF8StringEncoding]; 

출력 : UTF-8 문자의

2015-11-06 12:57:40.304 Test[10803:883182] Test 1: Read 1 byte(s): (null) 
2015-11-06 12:57:40.305 Test[10803:883182] Test 1: Read 1 byte(s): (null) 
2015-11-06 12:57:40.305 Test[10803:883182] Test 1: Concatenated: Б 

차, 길이 [1..6] 바이트에 누워있다.

#define MAX_UTF8_BYTES 6 
NSString *utf8String; 
NSMutableData *_data = [[NSMutableData alloc] init]; //for easy 'appending' bytes 

int bytes_read = 0; 
while (!utf8String) { 
    if (bytes_read > MAX_UTF8_BYTES) { 
     NSLog(@"Can't decode input byte array into UTF8."); 
     return; 
    } 
    else { 
     uint8_t byte[1]; 
     [_inputStream read:byte maxLength:1]; 
     [_data appendBytes:byte length:1]; 
     utf8String = [NSString stringWithUTF8String:[_data bytes]]; 
     bytes_read++; 
    } 
} 
: 당신이 NSInputStream 생의 바이트에서 읽은 후 UTF-8는 NSString로 번역하고자하는 경우

(1 byte) 0aaa aaaa   //if symbol lays in 0x00 .. 0x7F (ASCII) 
(2 bytes) 110x xxxx 10xx xxxx 
(3 bytes) 1110 xxxx 10xx xxxx 10xx xxxx 
(4 bytes) 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx 
(5 bytes) 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 
(6 bytes) 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 

그래서, 당신은 아마 당신이 유효한 문자열을 얻을 때까지 NSInputStream에서 바이트로 바이트를 읽고 싶어

0

ASCII (따라서 개행 문자)는 UTF-8의 부분 집합이므로, 임의의 충돌이있을 수없는 것이다.

간단한 ASCII 스트림에서와 마찬가지로 스트림을 개행 문자로 나눌 수 있어야합니다. 그런 다음 각 청크 ("라인")를 UTF-8을 사용하여 NSString으로 변환 할 수 있습니다.

인코딩 오류가 사실이 아니므로 스트림에 실제로 UTF-8 인코딩과 관련하여 잘못된 문자가 포함될 수 있습니까?

편집

은 코멘트에서 추가 :

이 선이 UTF-8로 변환하기 전에 메모리의 전체 라인을 유지하기 위해 충분히 몇 글자로 구성되어 있다고 가정합니다.

+0

두 번째 부분에 대해 옳았습니다. 문자열에 실제로 잘못된 문자/바이트가 포함되었습니다. 그러나 첫 번째 부분은 자명하지 않습니다. UTF-8 문자를 분리하고 'NSString'으로 변환 할 때 반쪽이 풀릴 수 있습니다. – Kreisquadratur

+0

사실 개행 문자는 멀티 바이트 문자를 작성하는 데 사용할 수 없습니다. UTF-8은 멀티 바이트에서 ASCII 문자가 사용되지 않음을 보장합니다.그러나 버퍼 크기가 읽을 문자열보다 작을 수 있기 때문에 분할이 발생할 수 있습니다. – Kreisquadratur

+0

@Kreisquadratur 아, 나는 그것을 해독하기 전에 전체 라인을 읽을 수 있다고 가정하고있었습니다. – Monolo