【问题标题】:Read binary file and count specific number c++读取二进制文件并计算特定数字c ++
【发布时间】:2017-07-01 19:51:06
【问题描述】:

大家好,我一直在到处寻找有关如何完成这项特定任务的见解。我看到了类似的东西,但没有明确的解释。我正在尝试读取 bin 文件并计算特定数字出现的次数。我看到了使用 .txt 文件的示例,使用 getline 似乎非常简单。我试图复制类似的结构,但使用二进制文件。

int main() {

    int searching = 3;
    int counter = 0;
    unsigned char * memblock;
    long long int size;

    //open bin file
    ifstream file;
    file.open("threesData.bin", ios:: in | ios::binary | ios::ate);

    //read bin file
    if (file.is_open()) {
        cout << "it opened\n";
        size = file.tellg();
        memblock = new unsigned char[size];
        file.seekg(0, ios::beg);
        file.read((char * ) memblock, size);

        while (file.read((char * ) memblock, size)) {
            for (int i = 0; i < size; i++) {
                (int) memblock[i];
                if (memblock[i] == searching) {
                    counter++;
                }
            }

        }
    }

    file.close();
    cout << "The number " << searching << " appears ";
    cout << counter << " times!";
    return 0;
}

当我运行程序时,很明显它打开了,但它不计算我正在搜索的数字。我做错了什么?

【问题讨论】:

  • 请记住,在二进制文件中,int 将(可能)是 4 个字节,而不是 UTF-8 或 ASCII 文本文件中的 1 个字节。您将使用 '\x03' 字节计算任何内容,这可能远远超出您的讨价还价。
  • 那么我应该将搜索更改为 uint32_t 吗?或者我的所有变量都应该指定为那种类型?因为我知道二进制文件包含 32 位整数。
  • 您应该将输入缓冲区转换为不同的类型。另外,我认为您的代码还有许多其他问题。您似乎在进入循环之前调用了file.read() 两次,您打开文件以使用起始位置(0)确定缓冲区大小,然后读取大小为0...选择一个合理的值:4096 左右。
  • 我会给你一些建议,但你应该考虑清楚:从缓冲区读取,确保size % sizeof(int) == 0,然后转换为int* int= = (int*)buffer并迭代for (size_t i = 0; i &lt; size / sizeof(int); ++i);这应该可以帮助您继续前进。
  • 感谢您的建议,我希望我能更清楚地理解它......所以我删除了额外的 file.read() 我认为我需要它来启动 while 循环......我认为 ios::ate 允许最初读取整个文件,然后 file.tellg() 会确定它的大小? ....所以对于我的缓冲区大小,我可以选择一个任意大的数字?...

标签: c++ file count binary


【解决方案1】:

您似乎正在考虑这一点,但这是我将如何去做。

  1. 用合理的大小初始化缓冲区。
  2. 将其转换为整数,因此您可以使用array[size_t] 语法来简化算术。
  3. 打开流,并在流有效时读取。
  4. 将读取的字节数转换为您期望的整数数。
  5. 为您发现的每个有效字符增加计数器。

代码

#include <fstream>
#include <iostream>


bool check_character(int value)
{
    return value == 3;
}


int main(void)
{
    // choose the size, cast a pointer as an int type, and initialize
    // our counter
    static constexpr size_t size = 4096;
    char* buffer = new char[size];
    int* ints = (int*) buffer;
    size_t counter = 0;

    // create our stream, 
    std::ifstream stream("file.bin", std::ios_base::binary);
    while (stream) {
        // keep reading while the stream is valid
        stream.read(buffer, size);
        auto count = stream.gcount();

        // we only want to go to the last valid integer
        // if we expect the file to be only integers,
        // we could do `assert(count % sizeof(int) == 0);
        // otherwise, we may have trailing characters

        // if we have trailing characters, we may want to move them
        // to the front of the buffer....
        auto chars = count / sizeof(int);           // floor division
        for (size_t i = 0; i < chars; ++i) {
            // false == 0, true == 1, so we can just add
            // if the value is 3
            counter += check_character(ints[i]);
        }
    }

    std::cout << "Counter is: " << counter << std::endl;

    delete[] buffer;
    return 0;
}

正如 NeilButterworth 指出的那样,您也可以使用向量。我不是很喜欢这个,而是“嗯”。

#include <fstream>
#include <iostream>
#include <vector>

/* ellipsed lines */

int main(void)
{
    /* ellipsed lines */
    static constexpr size_t size = 4096;
    std::vector<int> ints;
    ints.resize(size / sizeof(int));
    char* buffer = (char*) ints.data();
    /* ellipsed lines */

    /* ellipsed lines */
    std::cout << "Counter is: " << counter << std::endl;
    // no delete[]
    return 0;
}

【讨论】:

  • while (stream) { - 这不是您在循环中读取流的方式。您需要测试读取函数的返回值,而不仅仅是流状态。另外,请使用向量,而不是使用 new 分配的内存块。
  • @NeilButterworth,我可以做if (stream.read(buffer, size)),但这会返回流状态,但两者在功能上是等效的。下次读取调用发生时,gcount() 将返回 0,因此不会发生循环。我这样做是为了便于阅读。
  • @NeilButterworth,istream&amp; read (char* s, streamsize n); 是函数签名,while (stream) { stream.read(buffer, size) 只是 while (stream.read(buffer, size)) 的一个稍微冗长且性能稍差的版本。在这种情况下,实际上没有功能上的区别。
  • 对不起,当你说矢量而不是字符串时,我没有注意。删除了那条评论。但可以肯定的是,我可以使用向量,它在功能上基本上是等效的。它只是使清理工作更好一些。我现在将进行编辑。其余的,它是流状态。 @NeilButterworth
  • 谢谢亚历山大。这真的很整洁。我没有考虑使用布尔值在具有创造性的值为真时增加......而且我还没有看到 .gcount 用于这种分配。我认为这就是我正在寻找的用于替换 txt 文件的 getline ......我运行了这个程序,它似乎工作它产生了一个相当大的数字并且没有问题......但是当我评估它时,评估员给了我 60% 的错误代码。我不知道它在寻找什么,但我感谢您为帮助我而付出的努力。你给了我很多研究。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-01
  • 2011-09-03
  • 2016-01-15
  • 1970-01-01
  • 1970-01-01
  • 2011-02-03
  • 1970-01-01
相关资源
最近更新 更多