从NSData中查找不同的组件:NSData解析

时间:2013-12-24 12:32:10

标签: ios parsing nsdata

我的NSData格式为“Hello $ World $ Image”($用作Delimeter以区分不同的部分数据)我使用以下代码制作

NSData *data=[@"$" dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@",data);
NSData *data2=[@"Hello" dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@",data2);
NSData *data3=[@"World" dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"%@",data3);
NSData *dataImage=UIImagePNGRepresentation([UIImage imageNamed:@"Hello.png"]);
NSLog(@"%@",dataImage);


NSMutableData *mdata=[NSMutableData dataWithData:data2];
[mdata appendData:data];
[mdata appendData:data3];
[mdata appendData:data];
[mdata appendData:dataImage];
NSLog(@"%@",mdata);

从这里,我得到了mdata变量,它具有格式为Hello $ World $ Image的字节,

现在我想要反过来的事情,并希望得到Hello作为string1,World作为String2,并且Image存储在某个路径中,但我没有得到如何解析NSData为“$”并获取不同的组件。任何帮助将不胜感激。在此先感谢

2 个答案:

答案 0 :(得分:3)

鉴于您的评论是您坚持使用此$分隔格式,您应该参考Binary Data Programming Guide,其中介绍了如何从NSData中提取二进制数据。首先,要创建$分隔NSData,您可以执行以下操作:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Hello" ofType:@"png"];
NSData *imageData = [NSData dataWithContentsOfFile:path];

NSMutableData *data = [NSMutableData data];

[data appendData:[@"Hello" dataUsingEncoding:NSUTF8StringEncoding]];
[data appendData:[@"$" dataUsingEncoding:NSUTF8StringEncoding]];
[data appendData:[@"World" dataUsingEncoding:NSUTF8StringEncoding]];
[data appendData:[@"$" dataUsingEncoding:NSUTF8StringEncoding]];
[data appendData:imageData];

然后,要提取这两个字符串和图像,您可以:

NSUInteger len = [data length];

NSString *delimiterString = @"$";
NSData *delimiterData = [delimiterString dataUsingEncoding:NSUTF8StringEncoding];

NSRange firstDelimiterRange = [data rangeOfData:delimiterData
                                        options:0
                                          range:NSMakeRange(0, len)];

NSUInteger firstDelimiterIndex = firstDelimiterRange.location;
NSAssert(firstDelimiterIndex != NSNotFound, @"First delimiter not found");

NSRange secondDelimiterRange = [data rangeOfData:delimiterData
                                         options:0
                                           range:NSMakeRange(firstDelimiterIndex + 1, len - firstDelimiterIndex - 1)];

NSUInteger secondDelimiterIndex = secondDelimiterRange.location;
NSAssert(secondDelimiterIndex != NSNotFound, @"Second delimiter not found");

NSData   *subdata1 = [data subdataWithRange:NSMakeRange(0, firstDelimiterIndex)];
NSString *string1  = [[NSString alloc] initWithData:subdata1 encoding:NSUTF8StringEncoding];
NSAssert(string1, @"string1 not found");

NSData   *subdata2 = [data subdataWithRange:NSMakeRange(firstDelimiterIndex + 1, secondDelimiterIndex - firstDelimiterIndex - 1)];
NSString *string2  = [[NSString alloc] initWithData:subdata2 encoding:NSUTF8StringEncoding];
NSAssert(string2, @"string2 not found");

NSData   *subdata3 = [data subdataWithRange:NSMakeRange(secondDelimiterIndex + 1, len - secondDelimiterIndex - 1)];
UIImage  *image    = [UIImage imageWithData:subdata3];
NSAssert(image, @"valid image not found");

我在下面的原始答案侧重于可能更好的方法来存储两个字符串和一个二进制图像。鉴于您随后的评论,上面的丑陋代码可能对您有用,但我会保留原始答案以供将来参考。


有几点想法:

  1. 如果您只处理字符串(保证其中没有$),您可以像这样构建NSData

    NSData *data=[@"$" dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",data);
    NSData *data2=[@"Hello" dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",data2);
    NSData *data3=[@"World" dataUsingEncoding:NSUTF8StringEncoding];
    NSLog(@"%@",data3);
    
    NSMutableData *mdata=[NSMutableData dataWithData:data2];
    [mdata appendData:data];
    [mdata appendData:data3];
    NSLog(@"%@",mdata);
    

    然后你可以像这样提取字符串:

    NSString *fullString = [[NSString alloc] initWithData:mdata encoding:NSUTF8StringEncoding];
    NSArray  *components = [fullString componentsSeparatedByString:@"$"];
    NSLog(@"components = %@", components);
    

    但是,在处理图片时,您无法使用$分隔符,因为您无法保证dataImage可能没有0x24字节。

  2. 如果您必须使用$分隔符,则必须对图像数据进行一些编码(例如通过base64),以确保其中不会出现分隔符。例如:

    // fill `NSData` with contents of the image data
    
    NSString *path = [[NSBundle mainBundle] pathForResource:@"Hello" ofType:@"png"];
    NSData *data = [NSData dataWithContentsOfFile:path];
    
    NSString *imageBase64String;
    
    // base64 encode the binary data into a string format
    
    if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
        imageBase64String = [data base64EncodedStringWithOptions:0]; // iOS 7+
    } else {
        imageBase64String = [data base64Encoding];                   // pre-iOS7
    }
    
    NSArray *array = @[@"Hello", @"World", imageBase64String];
    NSString *finalString = [array componentsJoinedByString:@"$"];
    NSData *finalData = [finalString dataUsingEncoding:NSUTF8StringEncoding];
    

    显然,如果你在将图像添加到$分隔NSData时对图像进行base-64编码,那么在另一端,你必须将base-64字符串解码回图像在另一端。但希望这说明了这个想法。

  3. 在随后的评论中,您已经说过要通过此练习与服务器交换图像。通常,开发人员更喜欢使用完善的格式(如JSON或XML)与服务器交换数据。例如,考虑前一个示例中的array对象,您可以创建一个带有JSON表示的NSData

    NSError *error = nil;
    NSData *finalData = [NSJSONSerialization dataWithJSONObject:array options:0 error:&error];
    NSAssert(finalData, @"Unable to dataWithJSONObject: %@", error);
    

    这将产生一个看起来像的负载:

    ["Hello","World","iVBORw0KGgoAAAANSUh ... +Jyutq4AAAAASUVORK5CYII="]
    

    或者,更好的是,您可以使用字典(这使得每个元素的功能目的都清晰),但希望您能够理解:考虑使用完善的标准,如JSON,为您创建有效负载服务器

  4. 虽然您的后续评论已明确表示您正在执行此操作以与服务器交换图像,但如果您尝试将这三个对象(两个字符串和一个图像)放入{{1}要在您的应用程序中本地保存,更有效的机制是使用存档。因此,要创建NSData存档,您可以:

    NSData

    然后,从此存档中提取结果:

    NSArray *array = @[@"Hello", @"World", [UIImage imageNamed:@"Hello.png"]];
    NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
    

    有关详细信息,请参阅Archives and Serializations Programming Guide

    但鉴于您对将其发送到服务器的意见,存档可能不是正确的解决方案。

答案 1 :(得分:0)

我认为在这种情况下使用NSCoding是个好主意。您将需要创建具有一些属性的类并实现NSCoding协议方法。

查看使用它的任何示例,this首先是我在google中找到的,您可以使用任何