2013-12-11 55 views
0

我有一些數據從實驗記錄下來,保存爲二進制文件。記錄了許多電壓樣本,我告訴每個樣本是在0到0xFFFFFF範圍內的4字節無符號整數(無符號整數)。 因此,我試圖讀取C++中的二進制文件,執行將二進制數據轉換爲伏特的計算,並將這些值寫入.csv文件(從中可以將其導入到我的分析軟件中)。嘗試讀取4字節無符號整數的二進制文件並將其轉換爲伏特

問題: 我嘗試使用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; 
} 

回答

2
  • sizeof一無所知你讀取數據,它只是告訴你緩衝區的字節大小,這是30000*sizeof(int),在你的情況下(32位int)它是120000字節;
  • 由於sizeof告訴陣列的大小(而不是元素的數量),您的for的條件是錯誤的,它應該是i<totElems,其中totElems包含元素的總數;
  • 緩衝區應該是unsigned int或更好的類型uint32_tunsigned int不能保證是4字節)。
  • 如果您想要在volts中存儲浮點值,則必須創建該類型的數組floatdouble;但實際上,根本不需要volts數組 - 您只需將計算輸出寫入outFile,而不需要將其存儲在任何地方;
  • endl通過執行不必要的緩衝區刷新將無用地減慢你的程序;只是做<<'\n';
  • free(buffer)是完全錯誤的; free僅用於已使用malloc &朋友動態分配的內存,本地數組(如buffervolts)在該函數結束時自動釋放; (你也包括幾個實際沒有使用的POSIX頭文件);你可能會混淆C(fopen和& co。避免這種情況,可以用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
+0

此外:你的程序很有可能崩潰,因爲你正在'buffer'上執行'free',這是一個棧變量。刪除「免費」的電話。另外,爲什麼你使用C運行時庫'fopen'和朋友輸入,而C++'ofstream'輸出?選擇C或C++並保持一致。 –

+0

'buffer'的元素應該是'uint_least32_t'。 – Casey

+0

@Casey:不,他們需要'uint32_t'; 「最少」不會這樣做,因爲我們從文件中讀取非常特定類型的二進制表示(可能是32位小端無符號整數)。 –

相關問題