我手头有一个 NSMutableData 实例,我想使用输入流(类似于 Java 的 ByteArrayInputStream)从中读取。
我注意到 CFReadStream 有一个 initForReadingWithData 方法,但我不知道如何使用它。
任何人都可以提供有关如何使用它的示例位,或者如何以其他方式拥有内存输入流?
我手头有一个 NSMutableData 实例,我想使用输入流(类似于 Java 的 ByteArrayInputStream)从中读取。
我注意到 CFReadStream 有一个 initForReadingWithData 方法,但我不知道如何使用它。
任何人都可以提供有关如何使用它的示例位,或者如何以其他方式拥有内存输入流?
这是我达到的解决方案:
NSMutableData *msg;
CFReadStreamRef in = CFReadStreamCreateWithBytesNoCopy(nil, [msg mutableBytes], [_msg length], kCFAllocatorNull);
CFReadStreamOpen(in);
// read here as stream using CFReadStreamRead
CFRelease(in);
我注意到 CFReadStream 有一个 initForReadingWithData 方法,...</p>
嗯?CFReadStream 没有方法;它有功能。NSInputStream 有initWithData:
.
对于 NSInputStream,您需要成为流的委托人,打开流并响应其委托消息。其中大部分在抽象类NSStream中,它是 NSInputStream 和 NSOutputStream 的超类。
您可能会发现CFReadStream更易于使用,因为它让您只需调用一个函数即可直接从流中读取,而不必遵守异步“不要打电话给我,我会打电话给你”的要求。对于从网络读取,我建议不要这样做,但由于您是从内存缓冲区读取,它应该是无害的。
也就是说,创建流而不是自己遍历字节的主要原因是将其传递给接受任何流的东西,包括可能从网络读取的流。如果你正在实现那一面,你应该异步地这样做。
这个问题的答案取决于您是要读取数据并以类似于 NSStream 管理其数据的方式将其删除,还是要进行软读取并希望能够再次重新读取数据。
对于第一种方法,最简单的方法是创建一个 NSMutableData 类别,它将读取的字节数作为参数,然后让它在删除数据后返回数据。
#import "NSMutableData+Queue.h"
@implementation NSMutableData (Queue)
- (NSData *)read:(NSUInteger)length
{
if(length <= self.length && length > 0)
{
NSData *data = [self subdataWithRange:NSMakeRange(0, length)];
[self replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
return data;
}
return nil;
}
- (void)removeBytes:(NSUInteger)length
{
if(length <= self.length && length > 0)
{
[self replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
}
}
@end
第二种方法是编写一个类来管理 NSData 对象并对其执行软读取,同时保持对其偏移量的引用。
//
// CUDataReader.m
// Test
//
// Created by Abel Duarte on 10/28/15.
// Copyright © 2015 Abel Duarte. All rights reserved.
//
#import "CUDataReader.h"
@interface CUDataReader()
@property (nonatomic, assign) CUDataReaderEndianness endianness;
@property (nonatomic, retain) NSData *data;
@end
@implementation CUDataReader
#pragma mark - Init
- (id)initWithData:(NSData *)data
{
self = [super init];
if(self)
{
self.data = data;
self.offset = 0;
self.endianness = CUDataReaderDefaultEndian;
}
return self;
}
+ (id)dataReaderWithData:(NSData *)data
{
return [[CUDataReader alloc] initWithData:data];
}
- (void)dealloc
{
self.data = nil;
}
#pragma mark - Read
- (NSData *)read:(NSUInteger)length
{
NSUInteger readLength = self.offset + length;
if(readLength <= self.data.length && length > 0)
{
NSData *data = [self.data subdataWithRange:NSMakeRange(self.offset, length)];
self.offset += length;
return data;
}
return nil;
}
- (NSData *)readUntilData:(NSData *)data
{
NSRange dataRange = [self.data rangeOfData:data
options:0
range:NSMakeRange(self.offset, self.data.length - self.offset)];
if(dataRange.location != NSNotFound)
{
NSUInteger length = dataRange.location - self.offset;
return [self read:length];
}
return nil;
}
- (NSData *)readUntilDelimeter:(char)delimeter
{
NSData *data = [NSData dataWithBytes:&delimeter length:1];
return [self readUntilData:data];
}
#pragma mark - Endianess
- (void)setEndianness:(CUDataReaderEndianness)endianness
{
_endianness = endianness;
}
- (NSData *)endiannessDecodedData:(NSData *)data
{
if(self.endianness == CUDataReaderLittleEndian)
{
return data;
}
else
{
NSMutableData *endiannessDecodedData = [NSMutableData data];
NSUInteger length = data.length;
char *bytes = (char *)[data bytes];
for(NSInteger i = length - 1; i >= 0; i--)
{
char *byte = bytes + i;
[endiannessDecodedData appendBytes:byte length:1];
}
return endiannessDecodedData;
}
return data;
}
#pragma mark - Type utilities
- (BOOL)readBoolean
{
NSUInteger length = sizeof(BOOL);
return *(BOOL *)[[self endiannessDecodedData:[self read:length]] bytes];
}
- (char)readCharacter
{
NSUInteger length = sizeof(char);
return *(char *)[[self endiannessDecodedData:[self read:length]] bytes];
}
- (short)readShort
{
NSUInteger length = sizeof(short);
return *(short *)[[self endiannessDecodedData:[self read:length]] bytes];
}
- (int)readInteger
{
NSUInteger length = sizeof(int);
return *(int *)[[self endiannessDecodedData:[self read:length]] bytes];
}
- (float)readFloat
{
NSUInteger length = sizeof(float);
return *(float *)[[self endiannessDecodedData:[self read:length]] bytes];
}
- (double)readDouble
{
NSUInteger length = sizeof(double);
return *(double *)[[self endiannessDecodedData:[self read:length]] bytes];
}
- (long)readLong
{
NSUInteger length = sizeof(long);
return *(long *)[[self endiannessDecodedData:[self read:length]] bytes];
}
#pragma mark - Offset
- (void)rewind
{
self.offset = 0;
}
- (void)rewind:(NSUInteger)length
{
if(length <= self.offset)
{
self.offset -= length;
}
else
{
self.offset = 0;
}
}
- (void)setOffset:(NSUInteger)offset
{
if(offset <= self.data.length)
_offset = offset;
}
- (void)skip:(NSUInteger)offset
{
NSUInteger x = self.offset + offset;
[self setOffset:x];
}
- (NSUInteger)bytesRemaining
{
return self.data.length - self.offset;
}
@end