C++读取二进制文件出错

新手上路,请多包涵

我正在用QT写一个播放器,想判断打开的文件是否为合法的WMA格式,我选用的是fread函数,但读取结果与实际结果不同。程序如下:

bool Music::isLegal(QString media) {
    if(QFile(media).size() < 1024)
        return false;
    FILE *fp = fopen(media.toUtf8().data(),"rb");
    if(fp == nullptr)
        return false;
    size_t size = QFile(media).size();
    return Music::isWav(fp,size)||
            Music::isMP3(fp)||
            Music::isWma(fp)||
            Music::isAiff(fp,size);
}

其中isWma函数实现如下:

bool Music::isWma(FILE *media) {
    static constexpr int BASE = 16 / sizeof(uint);
    static const uint s[BASE] = {0x75b22630u,0x11cf668eu,0xaa00d9a6u,0x6cce6200u};
    uint *first_16B = new uint[BASE]();
    fread(first_16B,sizeof(uint),BASE,media);
    for(int i = 0; i < BASE; i++) {
        if(first_16B[i] != s[i])
            return false;
    }
    delete [] first_16B;
    return true;
}

但当我读取一个合法的WMA文件时却返回false。我知道这样判断不严谨,但当我使用其他编译器时却能够正确判断,请问这是为什么呢?

环境为QT5.12+MinGW(GCC 7.3)+Win10 X64

阅读 2.4k
3 个回答

错误:
return Music::isWav(fp,size)||

        Music::isMP3(fp)||
        Music::isWma(fp)||
        Music::isAiff(fp,size);

在或的关系中,如果第一个为false,那么再执行第二个,依次类推,所以当你判断到isWma时,前面读取的数据流已经到Wav+MP3头大小之后了,所以你每次读取之前移动读取指针到文件头,或者为了简洁放弃一点性能,不要传递fp参数,改成文件名

对这种需要直接操作二进制数据的,一般直接以byte为单位进行数据读写更准确,而uint之类的数据长度在不同的环境下(编译环境、运行环境)是可能不同的。


此外,根据文件头部数据,对文件格式进行判断,一般是对所有可能格式,先预取一次头部数据到内存,然后进行判断,这样可以只对文件读取一次,效率高很多的。

根据楼上的回答, 判断文件类型后, 用 fseek, 恢复指针就好了.

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题