二进制数据编程指南--<Binary Data Programming Guide>翻译

翻译连接https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/BinaryData/BinaryData.html#//apple_ref/doc/uid/10000037-SW1

简介

在Foundation框架和Core Foundation框架可以将二进制封装为对象并对其进行操作。因为数据对象是桥接对象,所以开发者可以交替使用Core Foundation数据对象和Foundation对象。数据对象可以自动管理字节缓冲区的内存开辟和内存释放。数据对象可以被存储在集合中,吸入属性列表,存储在文件中,以及在通讯端口之间进行传输。

本文档的结构

下面的文章介绍了数据对象是如何运作的
《数据对象》描述了数据对象是如何对缓冲字节进行封装的

下面的文章介绍了一般的任务
《二进制数据的使用》解释了如何创建和使用二进制数据对象
《可变二进制数据的使用》解释了如何修改二进制数据对象中的字节缓冲

数据对象

数据对象就是对缓冲字节进行面向对象化的封装。在这些数据对象中,简单开辟的缓存区(也就是不包含嵌套指针)具有其他对象的一些行为—也就是说,它们既能够包含数据,又能提供对这些数据的操作方法。数据对象通常被用来存储数据。数据对象在互联网以及内部网络的应用中非常有用,因为数据对象中被包含的数据可以在应用之间进行传输。
一个NSData或者NSMutableData对象所能够封装的数据大小取决于对应的平台限制,相关细节请参照NSData文档。当数据大小略大于几个内存页的时候,目标对象就会使用虚拟内存管理机制。数据对象还可以对已有数据进行封装,而不用考虑这些数据是如何被创建的。数据对象不会保存和缓冲数据有关的其他信息(比如数据的类型);如何使用数据取决于客户端。尤其要注意的是,数据对象并不负责在大小端设备之间的相关转换。取而代之的方案是,针对相关类型对象使用NSValue进行管理。
数据对象提供了一种与操作系统无关的方式来实现写时拷贝。所谓的写时拷贝技术就是说,当数据从虚拟内存进行拷贝的时候,只有操作方试图对目标数据进行修改的时候,才会真正地执行拷贝操作。
一种典型操作就是当创建一个数据对象的时候,可以指定缓存区的大小。开发者还可以提取指定范围的缓存数据,对两个数据对象的数据进行比较,以及将数据写入到对应的URL中。当创建了对应的对象之后,如果还有修改对象的需求,那么就应该使用可修改对象。在可修改对象中,开发者可以对数据进行截断、扩展、添加,以及替换。

使用二进制数据

本节包含NSData以及NSMutableData的相关代码示例。因为Foundation中的类簇机制,数据对象并不是NSData或者NSMutableData的实例,而是某个对应的私有子类的实例。尽管一个数据对象的类是私有的,但是接口是公开的,这些接口在父类NSData和NSMutableData中进行了声明。

基于原始字节创建数据对象

通常,开发者可以在NSData或者NSMutableData中通过那些以data...开头的方法来基于原始字节创建数据对象。这些方法可以返回包含开发者指定原始字节的数据对象。
通常初始化方法(诸如dataWithBytes:length:)会对传入的缓冲区字节进行拷贝。在这种情况下,被拷贝的
字节拥有者就是数据对象,由数据对象来负责对相关内存的释放。而原有缓冲字节的内存释放则由原有对象负责。
但是,如果开发者使用了带有NoCopy相关字样的初始化函数,那么对应的缓冲字节就不会被拷贝。这种情况下的数据对象会持有通过参数传入的缓冲字节,然后在对象释放的时候, 缓冲字节对应的内存可会被释放掉。(NSMutableData同样也有这些方法,但是缓冲字节会被拷贝,对应的缓冲区可会被立刻释放掉)。基于上述原因,通过NoCopy方法传入的数据必须是通过malloc创建的。
如果开发者倾向于不拷贝数据或者当对象释放的时候,缓存字节不被释放,那么就可以使用dataWithBytesNoCopy:length:freeWhenDone:以及initWithBytsNoCopy:length:freeWhenDone,然后通过对freeWhenDone:参数传入NO来达到目的。

基于文件或者URL创建数据对象

开发者可以使用dataWithContentsOfFile:以及dataWithContentsOfURL:这两个方法来创建数据对象。下面是实例代码,注意,路径必须是绝对路径。

NSString *thePath = @"/u/smith/myFile.txt";
NSData *myData = [NSData dataWithContentsOfFile:thePath];

访问和比较缓冲字节

NSData中的两个基础方法bytes和length为这个类的其他方法提供了基础操作。bytes方法返回一个指向缓冲字节数据的指针。length方法则返回了缓冲字节的长度。
NSData提供了从数据对象中拷贝到指定缓冲区的数据访问方法。getBytes:length:方法将字节拷贝到指定缓冲区去。比如说,下面的代码段就是初始化一个数据对象myData,参数是myString,然后使用了getByts:length:方法来将myData的数据拷贝到aBuffer中。

unsigned char aBuffer[20];

NSString *myString = @"Test string.";

const char *utfString = [myString UTF8String];

NSData *myData = [NSData dataWithBytes: utfString length: strlen(utfString)];

[myData getBytes:aBuffer length:20];

getBytes:range:方法将指定范围内的字节进行拷贝。
为了提取某个数据对象的字节数据子集,开发者可以使用subDataWithRange:方法。举例来说,下面的代码段会初始化一个数据对象data2来包含data1的数据子集。

NSString *myString = @"ABCDEFG";

const char *utfString = [myString UTF8String];

NSRange range = {2, 4};

NSData *data1, *data2;

data1 = [NSData dataWithBytes:utfString length:strlen(utfString)];

data2 = [data1 subdataWithRange:range];

如果想要比较两个数据对象是否相同,可以调用isEqualToData:方法,这个方法提供逐个字节的比较。

拷贝数据对象

开发者可以以拷贝的方式来创建一个只读的或者可修改的数据对象。NSData和NSMutableData实现了NSCopying协议以及NSMutableCopying协议,这就确保了可以在支队对象和可修改对象之间进行方便的转换。开发者可以通过调用copy方法来创建只读的拷贝,也可以通过mutableCopy来创建可修改的拷贝。

存储数据对象

开发者可以将字节数据存储在本地文件或者互联网中。writeToFile:atomically:方法以及writeToURL:atomically:方法可以让开发者将字节数据保存在本地文件中。

使用可变二进制数据

本节包含了一些和可变数据对象(也就是NSMutableData)有关的代码示例。开发者可以通过直接修改字节数组、添加新数据以及替换指定范围内的数据这些方式来改变可修改数据对象。

修改字节

NSMutableData的两个方法mutableBytes以及setLength:为本类的其他方法提供了基础。其中,mutableBytes返回的是一个指向可修改字节数据的指针。而setLength:方法允许开发者对数据对象中的缓冲字节进行范围扩展或者截断。increaseLengthBy:方法同样可以让开发者改变可修改数据对象中的数据长度。
在下面代码段中,mutableBytes可以返回一个指向data2的指针。然后使用data1的数据覆盖data2的数据。

代码段1,修改字节

NSMutableData *data1, *data2;

NSString *myString = @"string for data1";

NSString *yourString = @"string for data2";

const char *utfMyString = [myString UTF8String];

const char *utfYourString = [yourString UTF8String];

unsigned char *firstBuffer, secondBuffer[20];

/* initialize data1, data2, and secondBuffer... */

data1 = [NSMutableData dataWithBytes:utfMyString length:strlen(utfMyString)+1];

data2 = [NSMutableData dataWithBytes:utfYourString length:strlen(utfYourString)+1];

[data2 getBytes:secondBuffer length:20];

NSLog(@"data2 before: \"%s\"\n", (char *)secondBuffer);

firstBuffer = [data2 mutableBytes];

[data1 getBytes:firstBuffer length:[data2 length]];

NSLog(@"data1: \"%s\"\n", (char *)firstBuffer);

[data2 getBytes:secondBuffer length:20];

NSLog(@"data2 after: \"%s\"\n", (char *)secondBuffer);

下面是代码段1的输出:

Oct 3 15:59:51 [1113] data2 before: "string for data2"

Oct 3 15:59:51 [1113] data1: "string for data1"

Oct 3 15:59:51 [1113] data2 after: "string for data1"

添加字节

appendBytes:length:方法以及appendData:方法可以让开发者在可修改数据对象中进行数据添加。比如说,代码段2就是将data2中的数据拷贝到aBuffer中,然后将aBuffer中的数据添加到data1中

NSMutableData *data1, *data2;

NSString *firstString = @"ABCD";

NSString *secondString = @"EFGH";

const char *utfFirstString = [firstString UTF8String];

const char *utfSecondString = [secondString UTF8String];

unsigned char *aBuffer;

unsigned len;

data1 = [NSMutableData dataWithBytes:utfFirstString length:strlen(utfFirstString)];

data2 = [NSMutableData dataWithBytes:utfSecondString length:strlen(utfSecondString)];

len = [data2 length];

aBuffer = malloc(len);

[data2 getBytes:aBuffer length:[data2 length]];

[data1 appendBytes:aBuffer length:len];

程序的输出为ASCII的字符数组“ABCDEFGH”

替换字节

开发者可以通过方法resetBytesInRange:或者使用replaceBytesInRange:withBytes方法来将可修改数据对象中的指定范围的字节重置为0。在代码段3中,data1中的指定范围的数据被data2中的数据替代了,然后data1中的数据就从”Liz and John”变成了”Liz and Larry”。

NSMutableData *data1, *data2;

NSString *myString = @"Liz and John";

NSString *yourString = @"Larry";

const char *utfMyString = [myString UTF8String];

const char *utfYourString = [yourString UTF8String];

unsigned len;

unsigned char *aBuffer;

NSRange range = {8, strlen(utfYourString)};

data1 = [NSMutableData dataWithBytes:utfMyString length:strlen(utfMyString)];

data2 = [NSMutableData dataWithBytes:utfYourString length:strlen(utfYourString)];

len = [data2 length];

aBuffer = malloc(len);

[data2 getBytes:aBuffer length:len];

[data1 replaceBytesInRange:range withBytes:aBuffer];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容