Ios 有没有更有效的方法来比较C中的字节数组

Ios 有没有更有效的方法来比较C中的字节数组,ios,c,Ios,C,我试图通过查看前四个字节来检测给定文件是否为ZIP文件。这是在一个iOS应用程序中,所以文件句柄是由Cocoa框架处理的,但是实际的字节比较是C,我真的不知道 unsigned char aBuffer[4]; NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath]; NSData *data = [fileHandle readDataOfLength:4]; [

我试图通过查看前四个字节来检测给定文件是否为ZIP文件。这是在一个iOS应用程序中,所以文件句柄是由Cocoa框架处理的,但是实际的字节比较是C,我真的不知道

    unsigned char aBuffer[4];
    NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
    NSData *data = [fileHandle readDataOfLength:4];
    [data getBytes:aBuffer];
    if (aBuffer[0] == 0x50 && aBuffer[1] == 0x4b && aBuffer[2] == 0x03 && aBuffer[3] == 0x04) {
        archiveType = ARCHIVE_TYPE_ZIP;
    }
它起作用了,但我觉得很笨拙。有没有更好的方法来比较这4个字节?(是的,我知道它需要更多的错误检查。)

您可以使用。它就像strcmp一样,只是为了内存

if (memcmp([data bytes],"PK\3\4",4) == 0) {
    // success
}
也就是说,既然您使用的是Objective-C,那么您应该寻找比C更高级别的实现。我建议使用您期望的数据构建一个NSData,然后使用
[data isEqual:expectedData]

NSData *expectedHeader = [NSData dataWithBytes: "PK\3\4" length: 4];
if ([expectedHeader isEqual: data]) {
    // success
}
如果
isEqual:
,也可以使用
isequaldata:
。我更喜欢短标识符,但是
isEqualToData:
更有效,并且在暴露于不匹配的类型时抛出

你现在非常接近你的意图,而不是实际的机制

@jsd澄清说,他在寻找程序员的效率,而不是运行时的效率。但对于将来阅读本文的人来说:忘记运行时效率吧。您多久检查一次zip标头?相反,要担心代码有多简单,有多少方法会出错。并且在合适的时候总是倾向于更高层次的抽象。

你可以选择使用。它就像strcmp一样,只是为了内存

if (memcmp([data bytes],"PK\3\4",4) == 0) {
    // success
}
也就是说,既然您使用的是Objective-C,那么您应该寻找比C更高级别的实现。我建议使用您期望的数据构建一个NSData,然后使用
[data isEqual:expectedData]

NSData *expectedHeader = [NSData dataWithBytes: "PK\3\4" length: 4];
if ([expectedHeader isEqual: data]) {
    // success
}
如果
isEqual:
,也可以使用
isequaldata:
。我更喜欢短标识符,但是
isEqualToData:
更有效,并且在暴露于不匹配的类型时抛出

你现在非常接近你的意图,而不是实际的机制


@jsd澄清说,他在寻找程序员的效率,而不是运行时的效率。但对于将来阅读本文的人来说:忘记运行时效率吧。您多久检查一次zip标头?相反,要担心代码有多简单,有多少方法会出错。并且在合适的时候总是倾向于更高层次的抽象。

这很笨拙,但不太可能是低效的

另一种方法是使用C的函数。例如:

if(!memcmp(aBuffer, "PK\003\004", 4))
{
    archiveType = ARCHIVE_TYPE_ZIP;
}
您可能还希望剪切额外的缓冲区:

NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *data = [fileHandle readDataOfLength:4];
if ([data length] >= 4 && !memcmp([data bytes], "PK\003\004", 4))     
{
    archiveType = ARCHIVE_TYPE_ZIP;
}

C(因此,Objective-C)保证从左到右评估if语句,并在可能的情况下提前退出,因此这样先检查长度将明确避免
memcmp
越界。

这很笨拙,但不太可能是低效的

另一种方法是使用C的函数。例如:

if(!memcmp(aBuffer, "PK\003\004", 4))
{
    archiveType = ARCHIVE_TYPE_ZIP;
}
您可能还希望剪切额外的缓冲区:

NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *data = [fileHandle readDataOfLength:4];
if ([data length] >= 4 && !memcmp([data bytes], "PK\003\004", 4))     
{
    archiveType = ARCHIVE_TYPE_ZIP;
}

C(因此,Objective-C)保证从左到右评估if语句,并在可能的情况下提前退出,因此,这样先检查长度将明确避免
memcmp
越界。

您始终可以将
aBuffer
放在
联合中,因此您只需进行一次比较即可进行检查:

union {
  unsigned char asBytes[4];
  uint32_t asInt;
} aBuffer;
...
[data getBytes:aBuffer.asBytes];
if (aBuffer.asInt == 0x504b0304) { ... } // or 0x04034b50, depending on endianness

您可以始终将
aBuffer
放在
union
中,因此您只需进行一次比较即可进行检查:

union {
  unsigned char asBytes[4];
  uint32_t asInt;
} aBuffer;
...
[data getBytes:aBuffer.asBytes];
if (aBuffer.asInt == 0x504b0304) { ... } // or 0x04034b50, depending on endianness

我想不出比这更有效的方法了

编译器可能会很好地为您优化这一点

由于它只是一条不在循环中的语句,所以我不确定是否有理由手动优化它

您可以做的一件事是进行无符号长比较,如中所示

unsigned char fileCheck [4] = {0x50, 0x4b, 0x03, 0x04};
unsigned char aBuffer[4];

NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *data = [fileHandle readDataOfLength:4];
[data getBytes:aBuffer];

if (*(unsigned long *)aBuffer == *(unsigned long *)fileCheck) {
    // it is a file
    archiveType = ARCHIVE_TYPE_ZIP;
}

我想不出比这更有效的方法了

编译器可能会很好地为您优化这一点

由于它只是一条不在循环中的语句,所以我不确定是否有理由手动优化它

您可以做的一件事是进行无符号长比较,如中所示

unsigned char fileCheck [4] = {0x50, 0x4b, 0x03, 0x04};
unsigned char aBuffer[4];

NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:filePath];
NSData *data = [fileHandle readDataOfLength:4];
[data getBytes:aBuffer];

if (*(unsigned long *)aBuffer == *(unsigned long *)fileCheck) {
    // it is a file
    archiveType = ARCHIVE_TYPE_ZIP;
}

你试过以下方法吗

if (*((unsigned int *) aBuffer) == 'PK\3\4') {
    archiveType = ARCHIVE_TYPE_ZIP;
}
这应该适用于iPad和iPhone等iOS设备,因为它们的数据类型大小是一致的


那些否决我的人一定不熟悉多字符文字。

您尝试过以下方法吗

if (*((unsigned int *) aBuffer) == 'PK\3\4') {
    archiveType = ARCHIVE_TYPE_ZIP;
}
这应该适用于iPad和iPhone等iOS设备,因为它们的数据类型大小是一致的


那些向下投票的me必须不熟悉多字符文字。

添加一些可以比较的内容:
无符号字符引用缓冲区[4]={0x50,0x4b,0x03,0x04}
对于遵循普通的Cocoa约定,我非常喜欢
NSData-isEqual:
解决方案。为此,您可以使用合适的
NSData
键和
NSNumber
值为文件类型创建前四个字节的字典。这是否有助于简化整个代码?查找类型应该是一行,而不是一堆if语句。当我说“高效”时,我指的是程序员高效,而不是运行时高效。代码越短越好。我喜欢你使用两个NSData的想法,我不知道你可以用这样的C文本来构造它们。这就是我最后做的。唯一的区别是我使用了isEqualToData:而不是isEqual:。谢谢你这么好的回答。我真的以为你就是这个意思,我的意思是说,这显然是为了子孙后代,但我显然做得太差了。我将添加
等质量数据:
;我一直在使用
isEqual:
,因为它比较短,而且我没有做足够的比较来考虑性能。此外,我不打算将此添加到答案中,但是如果您担心额外的分配,您可以始终为
BytesaRequalto:(void*)ptr length:(nsInteger)添加一个类别长度
并在其中使用memcmp。类别非常适合移动概念上简单的c