Как я могу прочитать файл.spc из C++?
У меня есть файл сертификатов PKCS #7 (.spc), сгенерированный из некоторого оборудования. У него есть массив с плавающей точкой, который мне нужно прочитать в моей программе на C++.
Раньше я использовал внешнюю программу для создания файла.csv. Тем не менее, здесь я теряю некоторую точность, так как это позволит сохранить только 15 цифр. Это проблема, мне нужна точность.
Я искал вокруг некоторое время, но безрезультатно. Попытка использования fstream или boost mmap просто приводит к некоторому зашифрованному бреду...
Как это:
Fstream:
fstream iofile;
string path = "C:\\test.spc";
iofile.open(path.c_str());
if (iofile.is_open()) {
string s;
while (getline(iofile, s, '\n'))
cout << s << endl;
}
повысить Mmap:
boost::iostreams::mapped_file mmap("C:\\test.spc", boost::iostreams::mapped_file::readonly); // create RAM access mmap
auto f = mmap.const_data(); // set data to char array
auto l = f + mmap.size(); // used to detect end of file
string next = ""; // used to read in chars
for (; f && f != l; f++) {
cout << f[0] << endl;
}
Оба просто выводят случайные символы, которые не имеют смысла.
Обнаружил, что это двоичный формат. Итак, я попробовал это:
streampos size;
char * memblock;
ifstream file("C:\\test.spc", ios::in | ios::binary | ios::ate);
if (file.is_open())
{
size = file.tellg();
memblock = new char[size];
file.seekg(0, ios::beg);
file.read(memblock, size);
file.close();
for (unsigned int i = 0; i < size; i++)
cout << memblock[i];
cout << endl << "DONE" << endl;
cout << "the entire file content is in memory";
delete[] memblock;
}
else cout << "Unable to open file";
Который дал намного больше символов, чем раньше, но все же случайно.
Вот ссылка на файл: https://drive.google.com/a/uci.edu/file/d/0B3LD-8zOiOdza2FGSVNtbnlSVjQ/view?usp=sharing
2 ответа
Решаемые. Поскольку это бинарный файл, я пытался найти формат. Найдя его, я разместил ссылку с примерами файлов, кода и PDF-файла, объясняющего формат для всех, кому это нужно. Вот некоторый код на C++, который я написал, который читает его. Спасибо Reticulated Spline за помощь! https://drive.google.com/a/uci.edu/folderview?id=0B3LD-8zOiOdzfjY3YXJEdGlTZ2Z1ekJGNVlJalpYRmRkOHFFaFI4XzZEaWpFbldLSEt3LW8&usp=sharing
#include<stdio.h>
#include <iostream>
#include <iomanip>
#include <map>
using namespace std;
//reads in SPC files according to "new" spc format. Advised to read pdf file, see link below
//This shows how everything is set up, may not be entirely accurate depending on your implementation.
//You can skip memory blocks to make codes shorter, this just shows you what each value represents.
//See PDF for more details on each variable. https://drive.google.com/a/uci.edu/folderview?id=0B3LD-8zOiOdzfjY3YXJEdGlTZ2Z1ekJGNVlJalpYRmRkOHFFaFI4XzZEaWpFbldLSEt3LW8&usp=sharing
// Also includes example spc file
//Code is as is, I am not liable for any mishaps.
//Open source, do whatever you want with it
//Email for questions: tjohnsen@uci.edu
int main()
{
FILE *ptr_myfile;
// open file
ptr_myfile = fopen("c:\\testspc.spc", "rb"); // "rb" to read binary, use "wb" to write binary
if (!ptr_myfile) {
printf("Unable to open file!");
return 1;
}
// variables used to store different mem sizes
int i = 0; // int, 4 bytes
unsigned char b = 'a'; // byte, 1 byte
double d = 0; // double, 8 bytes
float f = 0; // float, 4 bytes
short int w = 0; // word, 2 bytes
// variables we actually need
int power2 = 0; // we use this to multiply to the y value (integer data value representing intensity) later
int numDataPoints = 0; // used to divide first and last x coord, for increments in x values (wavenumbers)
double firstXCoord = 0; // first logged x value (wavenumber)
double lastXCoord = 0; // last logged x value (Wavenumber
int numSubFiles = 1;
// keep track of data
// map< subfile#, map< wavenumber, intensity> > data
map<int, map< double, long double> > data;
// start main folder
fread(&b, sizeof(b), 1, ptr_myfile); // flags represent different things (see pdf)
fread(&b, sizeof(b), 1, ptr_myfile); // spc file version
fread(&b, sizeof(b), 1, ptr_myfile); // experiment type code
fread(&b, sizeof(b), 1, ptr_myfile); // IMPORTANT exponenet for Y values
power2 = (int)b; // save our exponent for multiplying
fread(&i, sizeof(i), 1, ptr_myfile); // IMPORTANT number of points in file
numDataPoints = i; // keep this to divide my min and max x values
fread(&d, sizeof(d), 1, ptr_myfile); // IMPORTANT first x coordinate
firstXCoord = d; // logs first x value (wavenumber)
fread(&d, sizeof(d), 1, ptr_myfile); // IMPORTANT last x coordinate
lastXCoord = d; // logs last x value (wavenumber)
fread(&i, sizeof(i), 1, ptr_myfile); // IMPORTANT Number of subfiles
numSubFiles = i; // keep track of how man spectra are being kept track of in this binary file
fread(&b, sizeof(b), 1, ptr_myfile); // X units type code
fread(&b, sizeof(b), 1, ptr_myfile); // Y units type code
fread(&b, sizeof(b), 1, ptr_myfile); // Z units type code
fread(&b, sizeof(b), 1, ptr_myfile); // Posting disposition
fread(&i, sizeof(i), 1, ptr_myfile); // compressed date (see pdf for format)
for (unsigned int j = 0; j < 9; j++) // resolution description text
fread(&b, sizeof(b), 1, ptr_myfile);
for (unsigned int j = 0; j < 9; j++) // source instrument description text
fread(&b, sizeof(b), 1, ptr_myfile);
fread(&w, sizeof(w), 1, ptr_myfile); // peak point number for interferograms
for (unsigned int j = 0; j < 8; j++) // spare
fread(&f, sizeof(f), 1, ptr_myfile);
for (unsigned int j = 0; j < 130; j++) // Memo
fread(&b, sizeof(b), 1, ptr_myfile);
for (unsigned int j = 0; j < 30; j++) // x, y, and z custom axis strings (combined)
fread(&b, sizeof(b), 1, ptr_myfile);
fread(&i, sizeof(i), 1, ptr_myfile); // byte offset to log block
fread(&i, sizeof(i), 1, ptr_myfile); // file modification flag
fread(&b, sizeof(b), 1, ptr_myfile); // processing code
fread(&b, sizeof(b), 1, ptr_myfile); // calibration level + 1
fread(&w, sizeof(w), 1, ptr_myfile); // sub method sample injection number
fread(&f, sizeof(f), 1, ptr_myfile); // floatind data multiplier concentration factor
for (unsigned int j = 0; j < 48; j++) // method file
fread(&b, sizeof(b), 1, ptr_myfile);
fread(&f, sizeof(f), 1, ptr_myfile); // Z subfile increment for even Z multifiles
fread(&i, sizeof(i), 1, ptr_myfile); // number of w planes
fread(&f, sizeof(f), 1, ptr_myfile); // w plane increment
fread(&b, sizeof(b), 1, ptr_myfile); // w axis units code
for (unsigned int j = 0; j < 187; j++) // reserved
fread(&b, sizeof(b), 1, ptr_myfile);
// end main header
// do this for all subfiles
for (unsigned int subFile = 0; subFile < numSubFiles; subFile++) {
// start sub folder for file (Even if only one file here)
fread(&b, sizeof(b), 1, ptr_myfile); // subfiles flags (See pdf)
fread(&b, sizeof(b), 1, ptr_myfile); // exponenet for sufiles y values
if ((int)b != 0) // my files at least had this area blank sinc had only one sub file
power2 = (int)b; // multiple sub files may have his changed, make sure to check other values for similar things
fread(&w, sizeof(w), 1, ptr_myfile); // subfile index number
fread(&f, sizeof(f), 1, ptr_myfile); // subfiels starting z value
fread(&f, sizeof(f), 1, ptr_myfile); // subfiles ending z value
fread(&f, sizeof(f), 1, ptr_myfile); // subfiles noise value to use peak picking
fread(&i, sizeof(i), 1, ptr_myfile); // number of points if XYXY multifile
fread(&i, sizeof(i), 1, ptr_myfile); // number of co-added scans
fread(&f, sizeof(f), 1, ptr_myfile); // w axis value
for (unsigned int j = 0; j < 4; j++) // reserved
fread(&b, sizeof(b), 1, ptr_myfile);
// end sub header for file
// get increment if just lists y values, and not in XY format
double increment = (lastXCoord - firstXCoord) / (numDataPoints-1);
double waveNumber = firstXCoord;
// start data entry for only x values
for (unsigned int j = 0; j < numDataPoints; j++) {
fread(&i, sizeof(i), 1, ptr_myfile); // read in data value
long double intensity = i * pow(2, power2) / (pow(2, 32)); // use pow(2, 16) in bottom fraction instead if data stored as 16-bit rather than 32-bit
data[subFile][waveNumber] = intensity; // store intensity
if ( j <= 5)
cout << waveNumber << " = " << intensity << endl;
waveNumber += increment; // add increment to x value
}
// end data for x values
}
fclose(ptr_myfile);
cout << "SPC FILE READ" << endl;
int k;
cin >> k;
return 0;
}
В ответ на сообщение user4513421 (я не знаю, как комментировать его сообщение): Супер спасибо за отличный код! В моем случае мне нужно было изменить эту строку: // начать ввод данных только для значений x для (unsigned int j = 0; j <numDataPoints; j++) {на это: // начать ввод данных только для значений x для (unsigned int j = 0; j <numDataPoints - 1; j++) {
Я думаю, что это ошибка в вашем коде, но я не уверен на 100%.