【问题标题】:How to read a NSInputStream with UTF-8?如何使用 UTF-8 读取 NSInputStream?
【发布时间】:2013-02-10 14:22:52
【问题描述】:

我尝试在 iOS 中使用 NSInputStream 读取一个大文件,以用换行符分隔文件(我不想使用 componentsSeparatedByCharactersInSet,因为它占用了太多内存)。

但由于并非所有行似乎都是 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): Б

【问题讨论】:

  • 那么,你的问题是什么?
  • @0x7fffffff 我添加了问题,抱歉。它也可能是双重的。

标签: ios utf-8 nsinputstream


【解决方案1】:

首先,在行中:s3 = [s1 stringByAppendingString:s2]; 您正在尝试连接到“nil”值。结果也将是“零”。因此,您可能想要连接字节而不是字符串:

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

输出:

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: Б

其次,UTF-8 字符的长度可能位于 [1..6] 字节中。

(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 读取原始字节,然后将它们转换为 UTF-8 NSString,您可能希望从 NSInputStream 逐字节读取,直到获得有效字符串:

#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++;
    }
}

【讨论】:

    【解决方案2】:

    ASCII(因此换行符)是 UTF-8 的子集,因此不应该有任何冲突。

    应该可以在换行符处划分流,就像在简单的 ASCII 流中一样。然后,您可以使用 UTF-8 将每个块(“行”)转换为 NSString

    您确定编码错误不是真实的,即您的流实际上可能包含与 UTF-8 编码相关的错误字符吗?

    已编辑以从 cmets 添加:

    这假定行包含足够少的字符以在从 UTF-8 转换之前将整行保留在内存中。

    【讨论】:

    • 您对第二部分是正确的:字符串实际上包含错误的字符/字节。然而,第一部分并非微不足道,因为您可能会在转换为 NSString 时拆分一个 UTF-8 字符并使其失去两半。
    • 实际上换行符不能用于组成多字节字符。 UTF-8 保证在多字节中不使用 ASCII 字符。但是可能会发生拆分,因为缓冲区大小可能小于要读取的字符串。
    • @Kreisquadratur 啊,我假设你可以在解码之前阅读整行。
    猜你喜欢
    • 2012-07-21
    • 2019-12-27
    • 2016-07-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    相关资源
    最近更新 更多