是否有更有效的方法来比较C中的字节数组

时间:2012-08-28 23:44:57

标签: ios c

我正在尝试通过查看前四个字节来检测给定文件是否是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个字节? (是的,我知道它需要更多错误检查。)

5 个答案:

答案 0 :(得分:5)

你可以使用memcmp。它就像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
}

如果isEqualToData:,您也可以使用isEqual:。我更喜欢短标识符,但isEqualToData:更有效,并且在遇到不匹配的类型时会抛出。

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

@jsd澄清说他正在寻找程序员效率,而不是运行时效率。但对于将来阅读本文的人来说:忘记运行时效率。你多久检查一次拉链头?相反,担心代码有多简单,以及它可能出错的方式有多少。并且在适合时总是支持更高级别的抽象。

答案 1 :(得分:2)

您可以随时将aBuffer放入union,这样您只需进行一次比较即可查看:

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

答案 2 :(得分:1)

我认为没有更有效的方式。

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

由于它只是一个不在循环或任何东西的单一陈述,我不确定是否有理由尝试手动优化它。

你可以做的一件事就是在

中进行无符号长比较
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;
}

答案 3 :(得分:0)

这是笨拙但不太可能低效。

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

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偏离界限。

答案 4 :(得分:-1)

您是否尝试过以下操作?

if (*((unsigned int *) aBuffer) == 'PK\3\4') {
    archiveType = ARCHIVE_TYPE_ZIP;
}

这适用于iPad和iPhone等iOS设备,数据类型大小一致。

那些贬低我的人必须不熟悉多字符文字。