为什么我要在这段代码中读取文件结尾?

时间:2018-10-01 11:09:25

标签: c++

我正在尝试围绕OpenAL实现一些简单的函数包装器。

当尝试逐个加载文件以通过多个缓冲区流式传输文件时,我莫名其妙地读取了eof。

#include <iostream>
#include <type_traits>
#include <cstring>
#include <fstream>

int32_t convert_to_int(char* buffer, std::size_t len, const std::endian endianess)
{
    int32_t a = 0;
    if(endianess == std::endian::little)
        std::memcpy(&a, buffer, len);
    else
        for(std::size_t i = 0; i < len; ++i)
            reinterpret_cast<char*>(&a)[3 - i] = buffer[i];
    return a;
}

bool load_wav_file_header(std::ifstream& file, uint8_t& channels, int32_t& sampleRate, uint8_t& bitsPerSample, int32_t& size)
{
    char buffer[4];
    if(!file.is_open())
        return false;

    // the RIFF
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read RIFF" << std::endl;
        return false;
    }
    if(std::strncmp(buffer, "RIFF", 4) != 0)
    {
        std::cerr << "ERROR: file is not a valid WAVE file (header doesn't begin with RIFF)" << std::endl;
        return false;
    }

    // the size of the file
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read size of file" << std::endl;
        return false;
    }

    // the WAVE
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read WAVE" << std::endl;
        return false;
    }
    if(std::strncmp(buffer, "WAVE", 4) != 0)
    {
        std::cerr << "ERROR: file is not a valid WAVE file (header doesn't contain WAVE)" << std::endl;
        return false;
    }

    // "fmt/0"
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read fmt/0" << std::endl;
        return false;
    }

    // this is always 16, the size of the fmt data chunk
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read the 16" << std::endl;
        return false;
    }

    // PCM should be 1?
    if(!file.read(buffer, 2))
    {
        std::cerr << "ERROR: could not read PCM" << std::endl;
        return false;
    }

    // the number of channels
    if(!file.read(buffer, 2))
    {
        std::cerr << "ERROR: could not read number of channels" << std::endl;
        return false;
    }
    channels = convert_to_int(buffer, 2, std::endian::little);

    // sample rate
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read sample rate" << std::endl;
        return false;
    }
    sampleRate = convert_to_int(buffer, 4, std::endian::little);

    // (sampleRate * bitsPerSample * channels) / 8
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read (sampleRate * bitsPerSample * channels) / 8" << std::endl;
        return false;
    }

    // ?? dafaq
    if(!file.read(buffer, 2))
    {
        std::cerr << "ERROR: could not read dafaq" << std::endl;
        return false;
    }

    // bitsPerSample
    if(!file.read(buffer, 2))
    {
        std::cerr << "ERROR: could not read bits per sample" << std::endl;
        return false;
    }
    bitsPerSample = convert_to_int(buffer, 2, std::endian::little);

    // data chunk header "data"
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read data chunk header" << std::endl;
        return false;
    }
    if(std::strncmp(buffer, "data", 4) != 0)
    {
        std::cerr << "ERROR: file is not a valid WAVE file (doesn't have 'data' tag)" << std::endl;
        return false;
    }

    // size of data
    if(!file.read(buffer, 4))
    {
        std::cerr << "ERROR: could not read data size" << std::endl;
        return false;
    }
    size = convert_to_int(buffer, 4, std::endian::little);

    /* cannot be at the end of file */
    if(file.eof())
    {
        std::cerr << "ERROR: reached EOF on the file" << std::endl;
        return false;
    }
    if(file.fail())
    {
        std::cerr << "ERROR: fail state set on the file" << std::endl;
        return false;
    }

    return true;
}

const int32_t BUFFER_SIZE = 320000;
const int32_t NUM_BUFFERS = 4;

int main()
{
    std::string filename = "Assets/session.wav";
    std::ifstream file;
    file.open(filename);
    if(!file.is_open())
    {
        std::cerr << "ERROR: could not open file \"" << filename << "\"" << std::endl;
        return false;
    }

    uint8_t channels;
    int32_t sampleRate;
    uint8_t bitsPerSample;
    int32_t size;
    if(!load_wav_file_header(file,channels,sampleRate,bitsPerSample,size))
    {
        std::cerr << "ERROR: could not open wav header of \"" << filename << "\"" << std::endl;
        return false;
    }

    char* data = new char[size];

    if(!file.read(data, size))
    {
        if(file.eof())
            std::cerr << "ERROR: reached end of file trying to read "
            << size << " bytes. Actually read " << file.gcount() << std::endl;
        else if(file.fail())
            std::cerr << "ERROR: fail state" << std::endl;
        else if(file.bad())
            perror(("error while reading file " + filename).c_str());
        return 0;
    }

    return 0;
}

程序的输出为:

ERROR: reached end of file trying to read 7035488 bytes. Actually read 554

根据cppreference,当您到达eof时,read会发生这种情况,它基于gcount(),看起来像我。问题在于该文件的总数为6,871 KB,否则.WAV文件中报告的大小大于它声称保留在其中的554。

0 个答案:

没有答案