正在尝试读取4字节无符号整数的二进制文件并转换为伏特

Trying to read a binary file for 4-byte unsigned integers and convert to volts

本文关键字:二进制文件 转换 无符号整数 读取 字节      更新时间:2023-10-16

我有一些实验记录的数据,保存为二进制文件。记录了许多电压样本,我被告知每个样本是0到0xFFFFFF范围内的4字节无符号整数(无符号整数)。因此,我正在尝试读取C++中的二进制文件,执行将二进制数据转换为伏特的计算,并将这些值写入.csv文件(从中我可以将其导入我的分析软件)。

问题:我尝试使用fread()将二进制文件放入一个名为"buffer"的数组中。它编译时没有给我一个错误,但数组的大小在某个地方变化到了原来大小的四倍,程序本身也崩溃了。它会将相同的值重复写入.csv文件。我使用fread()正确吗?

我尝试过的(在Notepad++中,使用Borland编译器):

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <fstream>
#include <iostream>
#include <cstdio>
using namespace std;
int main () {
    FILE * pFile;
    int buffer[30000];
    pFile = fopen ("00001001.e01", "rb");
    fread(buffer, 4, 30000, pFile); // Copy the file into the buffer:
    int buffsize = sizeof(buffer);
    cout << buffsize; //How big is the buffer?    It's 120000 now (error)
    //Open .csv file
    ofstream outFile;
    outFile.open("test.csv");
    /* Loop to calculate voltage V[i] to V[n]*/
    int volts[30000];
    for (int i=0; i < sizeof(buffer); i++)
    {
        volts[i] = 1.6 * (buffer[i] - 0x7FFFFF) / 0x7FFFFF;
        outFile << volts[i] << ";" << endl;    /* To write each calculated value to the .csv file.*/
    }; //Error - now writes 30000 values that are all same value - "817'
    // Terminate
    fclose (pFile);
    free (buffer);
    outFile.close();
    return 0;
}
  • sizeof对您读取的数据一无所知,它只是"告诉"您缓冲区的大小(以字节为单位),即30000*sizeof(int),在您的情况下(32位int)为120000字节
  • 由于sizeof告诉数组的字节大小(而不是元素的数量),所以for的条件是错误的,它应该是i<totElems,其中totElems包含元素的总数
  • 缓冲区应该是unsigned int类型,或者更好的是uint32_t类型(unsigned int不保证是4字节)
  • 如果要在volts中存储浮点值,则必须使该数组的类型为floatdouble;但实际上,您根本不需要volts数组——您只需将计算的输出写入outFile,而无需将其存储在任何位置
  • endl将通过执行不必要的缓冲区刷新来无用地减慢程序的速度;只做<<'n'
  • CCD_ 18完全错误;CCD_ 19仅用于已经使用CCD_;朋友,像buffervolts这样的本地数组在函数结束时自动释放
  • 您混合了C(fopen&co)和C++(fstream&co.)的内容(此外,您还包括了几个实际上没有使用的POSIX头);避免这种情况,用C或C++编写

所有这些,如果你事先知道元素的数量是30000;如果不是这样的话,你有不同的方法来解决这个问题:

  • 确定元素的数量(用fseek在文件的末尾,用ftell得到位置,除以元素大小,回到文件的开头),为它们分配足够的内存,按照您所做的读取它们,然后按照您已经做的进行;通常是个坏主意,你白白浪费了很多内存
  • 另一方面,最简单的方法实际上是去掉数组;从输入文件中读取单个值,计算转换后的值,并将其写入输出文件;继续下一个;当没有更多数据时终止循环(feof(pFile)返回非零值)
  • 通过大块读取数据,您可能会获得一些性能改进,但是,除非您正在处理非常大的文件,否则如果您对C和C++的了解有限,我会避免这样做

所以,我的建议是:坚持第二种方法。

综上所述,你可能会得到这样的结果:

#include <fstream>
#include <stdint.h>
int main()
{
    std::ifstream is("inputfile.dat", std::ios::binary);
    std::ofstream os("output.csv");
    uint32_t i;
    while(is.read((char *)&i, sizeof(i))) 
        os<<1.6*(i-0x7fffff)/0x7fffff<<";n";
    return 0;
}

备注:

  • 如果编译器不提供uint32_t,则应该删除<stdint.h>行,并使用unsigned int而不是uint32_t,也许可以添加assert(sizeof(unsigned int)==4)
  • 如果您必须处理多个文件,您可能应该设置输入和输出文件的命令行参数;使用argv