Прочитать двоичный файл, где каждый элемент представляет собой 2-байтовое целое число - PullRequest
0 голосов
/ 08 января 2019

У меня есть двоичный файл с расширением .b16, содержащаяся в виде целого числа без знака (диапазон 0..65535, расширение файла .b16, порядок байтов: младший / старший байт).

Основными файлами являются otypes03.b08 - otypes08.b08, otypes09.b16 и otypes10.b16. Они содержат координаты всех неэквивалентных наборы точек (типы заказов) для заданного числа n точек.

Я успешно прочитал все файлы с расширением .b08, однако, когда дело доходит до чтения файлов .b16, я не получаю ожидаемую информацию.

Что у меня есть на данный момент: (Это модифицированная версия алгоритма чтения, предназначенная исключительно для формата .b16)

int readPoints(int n, string file_name, vector<Point> & vPoints){
    ifstream input(file_name, std::ios::binary);
    if(input.fail()) return 1;

    vector< unsigned char> buffer(std::istreambuf_iterator<char>(input), {});
    //Copying each pair of binary points to a vector of Point objects
    Point temp;
    for( unsigned int i=0;i< buffer.size();i+=4){
        temp.x = buffer[i] | buffer[i+1]  ;
        temp.y = buffer[i+2] | buffer[i+3]  ;
        vPoints.push_back(temp);
    }
    return 0;
}

Каждый элемент файла - это координата точки на плоскости, однако кажется, что я читаю неправильно, считанные координаты не являются теми, которые должны быть. Я не знаю, что я делаю не так.

Что я использую для формата .b08:

//Reads a file of binary points and stores it on vector vPoints.
int readPoints(int n, string file_name, vector<Point> & vPoints){
    ifstream input(file_name, std::ios::binary);
    if(input.fail()) return 1;
    // copies all data into buffer
    //Stored as unsigned int. Arithmetic operations (+-*/) can be used! :)
    //Can be treated as signed int or unsigned int.
    vector< unsigned char> buffer(std::istreambuf_iterator<char>(input), {});
    //Copying each pair of binary points to a vector of Point objects
    Point temp;
    cout << "Buffer size: " << buffer.size() << endl;
    for( unsigned int i=0;i< buffer.size();i+=2){
        temp.x = buffer[i];
        temp.y = buffer[i+2];
        vPoints.push_back(temp);
    }
    return 0;
}

Более подробная информация о базе данных, которую я использую, находится здесь: http://www.ist.tugraz.at/aichholzer/research/rp/triangulations/ordertypes/

Файл, который я пытаюсь прочитать, это otypes09.b16, который составляет 5,7 МБ на тот случай, если вы захотите попробовать его.

Спасибо за ваше время.

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Вот один из методов:

uint8_t lsb;
uint8_t msb;
uint16_t value;
std::vector<uint16_t> database;
//...
input.read((char *) &lsb, sizeof(lsb));
input.read((char *) &msb, sizeof(msb));
value = msb * 256 + lsb;
database.push_back(value);

Поскольку это двоичный файл , используется метод read. Вы можете заменить назначение value на:
value = msb << 8 | lsb;
Хотя хороший компилятор должен перевести первое присваивание value во второе.

0 голосов
/ 09 января 2019

В подобных случаях, в зависимости от среднего значения данных и абсолютного разрешения, я предпочитаю использовать объединения. То, что вы могли бы сделать, это иметь объединение, которое имеет член int, а также структуру, содержащую 2 шорта. Каждый шорт будет содержать двоичную структуру из 2 16-битных целых.

Сказав это, приведенные выше ответы могут подойти вам. Есть много способов сделать что-то подобное, поэтому разработайте подходящий API для вас!

0 голосов
/ 08 января 2019
for( unsigned int i=0;i< buffer.size();i+=4){
    temp.x = buffer[i] | buffer[i+1]  ;
    temp.y = buffer[i+2] | buffer[i+3]  ;
    vPoints.push_back(temp);
}

Вышеприведенное неверно - вы делаете ИЛИ биты старших 8 бит поверх верхних 8 бит, что приводит к повреждению данных. Сначала нужно сдвинуть биты (какие биты нужно сдвинуть, зависит от того, хранит ли файл 16-разрядные слова в формате с прямым порядком байтов или в формате с прямым порядком байтов).

Если данные файла в формате с прямым порядком байтов, это должно работать:

// read in little-endian 16-bit words
for( unsigned int i=0;i< buffer.size();i+=4){
    temp.x = ((unsigned short)buffer[i+0]) | (((unsigned short)buffer[i+1])<<8);
    temp.y = ((unsigned short)buffer[i+2]) | (((unsigned short)buffer[i+3])<<8);
    vPoints.push_back(temp);
}

... или если данные файла хранятся в формате с прямым порядком байтов, это будет выглядеть примерно так:

// read in big-endian 16-bit words
for( unsigned int i=0;i< buffer.size();i+=4){
    temp.x = (((unsigned short)buffer[i+0])<<8) | ((unsigned short)buffer[i+1]);
    temp.y = (((unsigned short)buffer[i+2])<<8) | ((unsigned short)buffer[i+3]);
    vPoints.push_back(temp);
}
...