NSData的原理与实现
顾名思义,NSData是数据集合的抽象。更准确的说,NSData是一个字节序列。
一般我们可以将文件的内容读取到NSData中,也可以将NSData写入文件。NSData可以表示一个文件。处理NSData可以生成字符串,可以生成一张图片等。
NSData的成员是
@interface CCData : NSObject
void *_bytes;
NSUInteger _length;
}
_bytes指向字节数组,_length表示字节数组的长度。
NSData有许多初始化方法。其中- (instancetype)initWithBytesNoCopy:(void*)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b;最为重要,其他初始化方法调用该方法,完成初始化。
-(id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b
_bytes=NULL;
_length=0;
if(length>0)
if(bytes==NULL)
[NSException raise:NSInvalidArgumentException format:@"bytes == NULL"];
_bytes=bytes;
_length=length;
return self;
}
如果length为0,则_length为0,_bytes为NULL。如果length大于0,如果bytes为NULL,则抛出异常。否则_
bytes=bytes,_length=length,最后返回self。freeWhenDone参数无意义。
-(id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length
return [self initWithBytesNoCopy:bytes length:length freeWhenDone:YES];
}
调用- (instancetype)initWithBytesNoCopy:(void*)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b完成任务。
-(id)initWithBytes:(const void *)bytes length:(NSUInteger)length
void *buffer=NULL;
NSUInteger bufferSize=0;
if(length>0)
if(bytes==NULL)
[NSException raise:NSInvalidArgumentException format:@"bytes == NULL"];
buffer=malloc(length);
if(buffer==NULL)
[NSException raise:NSMallocException format:@"malloc out of memory"];
memcpy(buffer, bytes, length);
bufferSize=length;
self=[self initWithBytesNoCopy:buffer length:bufferSize];
if(buffer)
free(buffer);
return self;
如果length为0,则_length=0,_bytes为NULL。否则判断bytes是否为NULL,如果是则抛出异常。如果不为NULL,则用malloc申请数组 malloc(sizeof(char)*length),并复制数组内容。然后调用- (instancetype)initWithBytesNoCopy:(void*)bytes length:(NSUInteger)length。
- (nullable instancetype)initWithContentsOfFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr
//未实现
}
读取文件的内容到NSData中。参数path指定文件路径。readOptionsMask指定读取的方式。
errorPtr在读取出错时保存出错信息。readOptionsMask的可能值为
typedefNS_OPTIONS(NSUInteger, NSDataReadingOptions) {
NSDataReadingMappedIfSafe = 1UL << 0,
NSDataReadingUncached = 1UL << 1,
NSDataReadingMappedAlways NS_ENUM_AVAILABLE(10_7, 5_0) = 1UL << 3,
NSDataReadingMapped = NSDataReadingMappedIfSafe,
NSMappedRead = NSDataReadingMapped,
NSUncachedRead = NSDataReadingUncached
};
选项为NSDataReadingMappedIfSafe时文件读取使用mmap。
选项为NSDataReadingUncached时文件使用read读取。
选项为NSDataReadingMappedAlways时文件读取使用mmap。
-(id)initWithContentsOfFile:(NSString *)path
void *bytes;
NSUInteger length;
if(readContentsOfFile(path, &bytes, &length)==NO)
[self release];
return nil;
return [self initWithBytesNoCopy:bytes length:length];
}
static BOOL readContentsOfFile(NSString *path,void **buf,NSUInteger *len)
const char *lpath;
struct stat st;
off_t fileLength;
int fd;
void *tmp=NULL;
char fileBuf[4096];
size_t c;
if(path==nil)
return NO;
lpath=[path fileSystemRepresentation];
if(stat(lpath, &st)==-1)
return NO;
if((st.st_mode&S_IFMT)!=S_IFREG)
return NO;
fileLength=st.st_size;
fd=open(lpath, O_RDONLY);
if(fd==-1)
return NO;
if(fileLength!=0)
tmp=malloc(fileLength);
if(tmp==NULL)
return NO;
if(read(fd, tmp, fileLength)!=fileLength)
free(tmp);
return NO;
}else
tmp=NULL;
fileLength=0;
while ((c=read(fd, fileBuf, 4096))>0) {
if(tmp==NULL)
tmp=malloc(c);
}else
tmp=realloc(tmp, fileLength+c);
if(tmp==NULL)
free(tmp);
return NO;
memcpy(tmp+fileLength, fileBuf, c);
fileLength+=c;
*buf=tmp;
*len=fileLength;
return YES;
读取文件内容到NSData中。
- (nullable instancetype)initWithContentsOfURL:(NSURL *)url options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr
//未实现
}
读取url指定的文件内容到NSData中。参数url指定文件,参数readOptionsMask指定读取方式。
参数errorPtr在出错时保存出错信息。
- (id)initWithContentsOfURL:(NSURL *)url
return [self initWithContentsOfFile:[url path]];
}
读取url指定的文件的内容。
-(id)initWithData:(NSData *)data
if(data==nil)
[NSException raise:NSInvalidArgumentException format:@"data == nil"];
return [self initWithBytes:[data bytes] length:[data length]];
}
根据NSData对象初始化。如果参数data为nil,则抛出异常。否则调用- (instancetype)initWithBytes:(nullable constvoid*)bytes length:(NSUInteger)length方法。
初始化方法对应了一些构造方法。
+ (NSData *)data
return [[[NSData alloc] initWithBytesNoCopy:NULL length:0]autorelease];
}
构造空的NSData对象。
+ (NSData *)dataWithBytesNoCopy:(void*)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b
return return [[[NSData alloc] initWithBytesNoCopy:bytes length:length freeWhenDone:b]autorelease];
}
根据字节数组构造NSData对象。不复制字节数组。
+ (NSData *)dataWithBytesNoCopy:(void*)bytes length:(NSUInteger)length
return return [[[NSData alloc] initWithBytesNoCopy:bytes length:length]autorelease];
}
根据字节数组构造NSData对象。不复制字节数组。
+ (NSData *)dataWithBytes:(nullable constvoid*)bytes length:(NSUInteger)length
return return [[[NSData alloc] initWithBytes:bytes length:length]autorelease];
}
根据字节数组构造NSData对象。
+ (NSData *)dataWithContentsOfFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr
return [[[NSData alloc] initWithContentsOfFile:path options:readOptionsMask error:errorPtr] autorelease];
}
读取文件内容构造NSData对象。
+ (NSData *)dataWithContentsOfURL:(NSURL *)url options:(NSDataReadingOptions)readOptionsMask error:(NSError **)errorPtr
return [[[NSData alloc] initWithContentsOfURL:url options:readOptionsMask error:errorPtr] autorelease];
}
读取url指定的文件构造NSData对象。
+ (NSData *)dataWithContentsOfFile:(NSString *)path
return [[[NSData alloc] initWithContentsOfFile:path] autorelease];
}
读取文件内容构造NSData对象。
+ (NSData *)dataWithContentsOfURL:(NSURL *)url
return [[[NSData alloc] initWithContentsOfURL:url] autorelease];
}
读取url指定的文件构造NSData对象。
+(NSData *)dataWithData:(NSData *)data
return [[[NSData alloc] initWithData:data] autorelease];
}
根据NSData对象构造NSData对象。
以下是NSData常用的方法。
-(NSUInteger) length
return _length;
}
返回字节数组的大小。
-(const void *)bytes
return _bytes;
}
返回字节数组。
-(void)getBytes:(void *)buffer
[self getBytes:buffer range:NSMakeRange(0, _length)];
获取字节数组。
-(void)getBytes:(void *)buffer length:(NSUInteger)length
[self getBytes:buffer range:NSMakeRange(0, length)];
}
获取字节数组,获取的字节数组长度为length。
-(void)getBytes:(void *)buffer range:(NSRange)range
if(buffer==NULL)
[NSException raise:NSInvalidArgumentException format:@"buffer == NULL"];
if(range.location>_length||range.length>_length-range.location)
[NSException raise:NSRangeException format:@"range out of count"];
memcpy(buffer, _bytes+range.location, range.length);
}
获取range区间内的字节数组。
-(BOOL)isEqualToData:(NSData *)other
if(other==nil)
[NSException raise:NSInvalidArgumentException format:@"other is nil"];
if(self==other)
return YES;
if(_length!=[other length])
return NO;
if(memcmp(_bytes, [other bytes], _length)==0)
return YES;
return NO;
}
判断NSData是否相等。
-(NSData *)subdataWithRange:(NSRange)range
if(range.location>_length||range.length>_length-range.location)
[NSException raise:NSRangeException format:@"range out of count"];
void *bytes=NULL;
NSUInteger length=0;
if(range.length>0)
bytes=malloc(range.length);
if(bytes==NULL)
[NSException raise:NSMallocException format:@"malloc out of memory"];
memcpy(bytes, _bytes+range.location, range.length);
length=range.length;
self=[self initWithBytesNoCopy:bytes length:length];
if(bytes)
free(bytes);
return [self autorelease];
}
获取字节序列的子序列。
-(BOOL)writeToFile:(NSString *)path atomically:(BOOL)useAuxiliaryFile
const char *lpath=[path fileSystemRepresentation];
int fd=open(lpath, O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd==-1)
return NO;
if(write(fd, _bytes, _length)!=_length)
return NO;
close(fd);
return YES;
写入文件。
- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically
return [self writeToFile:[url path] atomically:atomically];
}
写入url指定的文件。
- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)writeOptionsMask error:(NSError **)errorPtr
//未实现
}
写入文件。path指定文件路径,writeOptionsMask指定写入方式。errorPtr在出错时保存出错信息。writeOptionsMask的可能值是
typedefNS_OPTIONS(NSUInteger, NSDataWritingOptions) {
NSDataWritingAtomic = 1UL << 0,
NSDataWritingWithoutOverwriting NS_ENUM_AVAILABLE(10_8, 6_0) = 1UL << 1,
NSDataWritingFileProtectionNone NS_ENUM_AVAILABLE_IOS(4_0) = 0x10000000,
NSDataWritingFileProtectionComplete NS_ENUM_AVAILABLE_IOS(4_0) = 0x20000000,
NSDataWritingFileProtectionCompleteUnlessOpen NS_ENUM_AVAILABLE_IOS(5_0) = 0x30000000,
NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication NS_ENUM_AVAILABLE_IOS(5_0) = 0x40000000,
NSDataWritingFileProtectionMask NS_ENUM_AVAILABLE_IOS(4_0) = 0xf0000000,
NSAtomicWrite = NSDataWritingAtomic
};
- (BOOL)writeToURL:(NSURL *)url options:(NSDataWritingOptions)writeOptionsMask error:(NSError **)errorPtr
//未实现
}
写入url指定的文件。
- (NSRange)rangeOfData:(NSData *)dataToFind options:(NSDataSearchOptions)mask range:(NSRange)searchRange
}
搜索字节序列。dataToFind是搜索的字节序列,searchRange是搜索的区间,mask是搜索的模式。其可能值是
typedefNS_OPTIONS(NSUInteger, NSDataSearchOptions) {
NSDataSearchBackwards = 1UL << 0,
NSDataSearchAnchored = 1UL << 1
}
NSDataSearchBackwards是由后向前搜索。
NSDataSearchAnchored是由前向后搜索。
NSData是不可变的,不能添加删除。NSMutableData是Data的可变版本。NSMutableData继承自NSData。继承了NSData的都有方法。
NSMutableData的成员是
@interface CCMutableData : CCData
//void *_bytes;
//NSUInteger _length;
NSUInteger _capacity;
NSUInteger _grow;
@end
-(id)initWithCapacity:(NSUInteger)capacity
if(capacity==0)
capacity=1;
_bytes=malloc(capacity);
if(_bytes==NULL)
[NSException raise:NSMallocException format:@"malloc out of memory"];
_capacity=capacity;
_length=0;
_grow=capacity/2;
if(_grow==0)
_grow=1;
return self;
}
根据容量初始化NSMutableData。
- (id)initWithBytes:(const void *)bytes length:(NSUInteger)length
[self initWithCapacity:length];
if(length>0)
if(bytes==NULL)
[NSException raise:NSInvalidArgumentException format:@"bytes is null"];
memcpy(_bytes, bytes, length);
_length=length;
return self;
根据字节数组初始化NSMutableData。
-(id)initWithBytesNoCopy:(void *)bytes length:(NSUInteger)length freeWhenDone:(BOOL)b
_bytes=malloc(1);
_length=0;
_capacity=1;
_grow=1;
if(_bytes==NULL)
[NSException raise:NSMallocException format:@"malloc out of memory"];
if(length>0)
if(bytes==NULL)
[NSException raise:NSInvalidArgumentException format:@"bytes == NULL"];
free(bytes);
_bytes=bytes;
_capacity=length;
_length=length;
_grow=_capacity/2;
if(_grow==0)
_grow=1;
return self;
}
根据字节数组初始化NSMutableData。
-(id)initWithLength:(NSUInteger)length
[self initWithCapacity:length];
memset(_bytes, 0, length);
_length=length;
return self;
}
根据长度初始化数据,数据都为0.
+ (NSMutableData *)dataWithCapacity:(NSUInteger)aNumItems
return [[[NSMutableData alloc] initWithCapacity:aNumItems] autorelease];
}
根据容量构建数据
+ (NSMutableData *)dataWithLength:(NSUInteger)length
return [[NSMutableData alloc] initWithLength:length] autorelease];
}
根据长度构建数据。
-(void *)mutableBytes
return _bytes;
}
返回字节序列
-(void)_grow:(NSUInteger)max
if(max>_capacity)
while (max>_capacity) {
_capacity+=_grow;
_grow=_capacity/2;
_bytes=realloc(_bytes, _capacity);
}
增长容量。
-(void)appendBytes:(const void *)bytes length:(NSUInteger)length
if(length>0)
if(bytes==NULL)
[NSException raise:NSInvalidArgumentException format:@"bytes == 0"];
NSUInteger oldLength=_length;
NSUInteger newLength=_length+length;
if(newLength>_capacity)
[self _grow:newLength];
memcpy(_bytes+oldLength, bytes, length);
_length=newLength;
添加字节序列。
-(void)appendData:(NSData *)other
if(other==nil)
[NSException raise:NSInvalidArgumentException format:@"other is nil"];
[self appendBytes:[other bytes] length:[other length]];
}
添加数据
- (void)increaseLengthBy:(NSUInteger)extraLength
NSUInteger oldLength=_length;
NSUInteger newLength=_length+extraLength;
[self _grow:newLength];
memset(_bytes+oldLength, 0, extraLength);
}
增长数据。
- (void)replaceBytesInRange:(NSRange)range withBytes:(const void *)bytes
if(range.location>_length)
[NSException raise:NSRangeException format:@"location out of length"];
if(range.length>0)
if(bytes==NULL)
[NSException raise:NSInvalidArgumentException format:@"bytes is null"];
NSUInteger newLength=range.location+range.length;
if(newLength>_length)
[self _grow:newLength];
_length=newLength;
memcpy(_bytes+range.location,bytes,range.length);
替换区间内的字节
- (void)resetBytesInRange:(NSRange)range
if(range.location>_length||range.length>_length-range.location)
[NSException raise:NSRangeException format:@"range out of length"];
memset(_bytes+range.location, 0, range.length);
}
重置区间内的数据
- (void)setData:(NSData *)data
if(data==nil)
[NSException raise:NSInvalidArgumentException format:@"data is nil"];
[self _grow:[data length]];