0

次の関数は機能していません。つまり、終了します。

fread(buf, 1, 4, stdin);
buf[4] = '\0';

if (strcmp((char*)buf, "data")) exit(EXIT_FAILURE);

手動でfreadをストリームのさらに下にプッシュできれば、最終的には「データ」に到達すると思います。

言い換えると、バイトをスキップするようにfreadをインクリメントするにはどうすればよいですか。

コードの例は常にありがたいです。

ありがとう!


編集1

基本的に、iPhoneでwavファイルのヘッダーを解析しています。それは私にいくつかの問題を与えています、そしてそれはアップルがそのオーディオファイルをフォーマットする方法に関係していると私は信じています。誰かが私に「データ」を取得するまでストリームを実行し、そこから先に進むことを勧めました。

これで物事が明確になることを願っています。


編集2

これはwavファイルヘッダーがどのように見えるべきかについてのドキュメントですが、アップルがそれらをフォーマットする方法がこれを不正確にするかどうか疑問に思います。

'data'が4の倍数である36だけオフセットされていることに気付くでしょう。

4

3 に答える 3

2

これは、ファッションのようなストリームで機能し、私が望むことを実行します。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char** argv)
{
    long pos = 0;
    char buf;
    char str[5] = {'\0','\0','\0','\0','\0'};

    while ( fread(&buf, sizeof(char), 1, stdin) > 0 )
    {
        pos++;
        str[0] = str[1]; 
        str[1] = str[2];
        str[2] = str[3];

        str[3] = buf;
        str[4] = '\0';

        /* uncomment to see what got read ** printf("Read %s\n", str); */

        if ( strcmp(str, "data") == 0 )
        {
            break;
        }
    }


    printf("\"data\" occured after %ld bytes\n", pos);
    return 0;
}

これは、私が呼び出したバッファーを使用し、strその中の位置を回転させることによって機能します。が表示されるまで動作しdataます。

テキストではなく、バイナリデータを読み取ることに注意してください。したがって、stdinのすべてが読み取られ、改行が含まれます。ただし、それをファイルハンドルに適合させると、問題にはなりません。

おそらくこれを含めることができます。使用に関する問題freadは、設計によるものです。

ストリームのファイル位置インジケータ(定義されている場合)は、正常に読み取られたバイト数だけ進められます。

したがって、一度に4バイト進むと、データがデータの先頭から正確に4の倍数でない限り、それを見逃すことになります。例えば:

123DATA

一度に4バイトを読み取ると失敗します。

さて、これが文書化されたファイル形式であることを考えると、ヘッダーのフィールドの幅を正確に示すヘッダー仕様はどこかにありませんか?または、少なくともそれらが変化する場所で、適切に読み取ることができますか?うまくいくまで読むdataが、本当にエレガントではない。

または、さらに良いことに、これを行うためのライブラリがどこかにあるはずです。


編集Waveファイルのヘッダーに応答して、固定されていてそれほど大きくないため、すべてをバッファーに読み込みます。

uint8_t* hdr = malloc(36*sizeof(uint8_t));
fread(hdr, sizeof(uint8_t), 36);

解放することを忘れないでください。この時点で、ヘッダー全体が抽出されています。私はuint8_t間違いなく8ビットでした。この段階で、そのデータを構造体にキャストするなど、いくつかの興味深いトリックを引き出すことができます。フィールドのエンディアンに注意してください。

それ以降、ストリームはチャンクで利用できるようになると思います。あなたがする必要がある最初のことはこれです:

uint8_t chkid;
uint8_t chksz;
fread(&chkid, sizeof(uint8_t), 4, stream);
fread(&chksz, sizeof(uint8_t), 4, stream);

これにより、その特定のチャンクのデータが取得されます。リトルエンディアンシステムを使用していると仮定するとchksz、この時点で整数として直接使用できるはずなので、次のことができます。

uint8_t dataframe = malloc(chksz * sizeof(uint8_t));

データを読み取ることができる場所:

fread(&dataframe, sizeof(uint8_t), chksz, stream);

もちろん、これはAppleのウェーブフォーマットが説明されているものであることを前提としています。さて、そのページから:

WAVEファイル形式は、マルチメディアファイルの保存に関するMicrosoftのRIFF仕様のサブセットです。RIFFファイルは、ファイルヘッダーで始まり、その後に一連のデータチャンクが続きます。WAVEファイルは、多くの場合、2つのサブチャンク(データ形式を指定する「fmt」チャンクと実際のサンプルデータを含む「data」チャンク)で構成される単一の「WAVE」チャンクを持つ単なるRIFFファイルです。この形を「標準形」と呼びます。それが実際にどのように機能するかを誰が知っていますか。

ストリームに何もなくなるまで継続的なループで使用すると、RIFFのデータチャンクをいくつでも読み取ることができるようになるという指示を与えました。次に、取得したデータを適切に処理して分解する必要があります。つまり、読み込んだデータチャンクを適切に分割します。これが読み取ることを期待する唯一の形式である場合は、追加のチャンクを無視することができます。

さて、問題は残っています。アップルのフォーマットとは何ですか。正直なところ、私にはわかりません。

于 2011-02-16T13:06:02.527 に答える
1

dataこれらの4バイトはWAV形式の形式チャンクの一部としても発生する可能性があるため、ASCIIで最初に出現するのがデータヘッダーの先頭であるとは限りません。WAVを解析するためのより良い方法は(テストされていない)

/* Returns the size of the data payload */
off_t skip_to_data_payload(FILE *fp)
{
    unsigned char buf[4];
    int i;
    off_t size;

    // the "data" magic should start at byte 36
    for (i=0; i<9; i++)
        fread(buf, 1, 4, fp);
    fread(buf, 1, 4, fp);
    if (memcmp(buf, "data", 4) != 0)
        return (off_t)(-1);

    // read size, assume little-endian
    fread(buf, 1, 4, fp);
    off_t size = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[4] << 24);

    return size;
}

注:PCMエンコーディングとリトルエンディアンファイルを想定しています。Appleは過去にビッグエンディアンプロセッサを使用したことがあるので、実際にそれをチェックする必要があります。(またはライブラリを使用します。)

于 2011-02-16T13:14:18.313 に答える
0

文字列の終了(\ 0)に追加の文字が必要であり、文字列の4文字すべてをすでに使い果たしているため、このstrcmpは機能しません。strncmp代わりに試してください。また、stdinの操作中に文字を追加する場合は、改行を忘れないでください。

于 2011-02-16T12:38:40.723 に答える