0

以下功能不起作用,即退出:

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

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

我想如果我可以手动将 fread 推到更远的流中,它最终会击中“数据”。

换句话说,我如何增加 fread 以便它跳过字节。

代码示例总是很受欢迎。

谢谢!


编辑 1

基本上我正在解析 iPhone 上的 wav 文件的标题。这给我带来了一些麻烦,我相信这与苹果格式化其音频文件的方式有关。有人建议我在流中运行,直到我得到“数据”,然后从那里继续前进。

我希望这能澄清事情。


编辑 2

这是关于 wav 文件头应该是什么样子的文档,但我想知道苹果格式化他们的方式是否会导致这不准确。

您会注意到“数据”偏移了 36,这是 4 的倍数。

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工作,但并不优雅,真的。

或者,更好的是,我确信一定有一个图书馆可以在某个地方这样做。


编辑响应波形文件的标题,因为它是固定的并且不是那么大,所以将整个内容读入缓冲区。

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 文件通常只是一个带有单个“WAVE”块的 RIFF 文件,该块由两个子块组成——一个指定数据格式的“fmt”块和一个包含实际样本数据的“数据”块。将此形式称为“规范形式”。谁知道这一切是如何运作的。

我已经给你说明,如果在连续循环中使用直到流中没有更多内容,将允许你读取任意数量的数据块 a-la RIFF。然后,您需要适当地处理获得的数据以将其分解;即适当地拆分您读入的数据块。如果这是您希望阅读的唯一格式,您可以忽略其他块。

现在,问题仍然存在,什么是苹果格式,老实说我不知道​​!

于 2011-02-16T13:06:02.527 回答
1

我不认为dataASCII 中的第一次出现是数据头的开始,因为这四个字节也可能作为WAV 格式的格式块的一部分出现。解析 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

该 strcmp 将永远无法工作,因为您需要一个额外的字符作为字符串终止 (\0) 并且您已经用完了字符串的所有 4 个字符。试试strncmp吧。如果您在使用标准输入时添加了更多字符,请不要忘记换行。

于 2011-02-16T12:38:40.723 回答