1

最初の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バイトを比較するためのより良い方法はありますか?(はい、もっとエラーチェックが必要なことはわかっています。)

4

5 に答える 5

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は、実行時の効率ではなく、プログラマーの効率を求めていることを明らかにしました。しかし、将来これを読む人のために:実行時の効率を忘れてください。zipヘッダーをチェックする頻度はどれくらいですか。代わりに、コードがいかに単純で、コードがうまくいかない可能性があるかについて心配してください。そして、それらが適合するときは、常により高いレベルの抽象化を支持します。

于 2012-08-28T23:48:51.287 に答える
2

いつでもを入れることができるのでaBufferunion1つの比較だけで確認できます。

union {
  unsigned char asBytes[4];
  uint32_t asInt;
} aBuffer;
...
[data getBytes:aBuffer.asBytes];
if (aBuffer.asInt == 0x504b0304) { ... } // or 0x04034b50, depending on endianness
于 2012-08-28T23:54:02.793 に答える
1

私が考えることができるより効率的な方法は本当にありません。

コンパイラはおそらくこれを最適化するための素晴らしい仕事をするでしょう。

また、ループなどに含まれていないのは1つのステートメントだけなので、手動で最適化しようとする理由があるかどうかはわかりません。

あなたができることの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;
}
于 2012-08-28T23:56:41.763 に答える
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ことで、範囲外のふらつきを明示的に回避できます。

于 2012-08-28T23:50:58.120 に答える
-1

次のことを試しましたか?

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

これは、データ型のサイズが一貫しているiPadやiPhoneなどのiOSデバイスで機能するはずです。

私に反対票を投じる人は、複数文字のリテラルに精通していてはなりません。

于 2012-08-28T23:59:21.597 に答える