Чтение Бинарного файла . Задача С++

138
11 июня 2019, 17:30

Есть задание по С++: https://drive.google.com/file/d/0B7zD9kDjFhBzSzJWd1kzcHNWWXNzWkpaaHNQWGtxUXFvQ3Fz/view?usp=sharing

Сам бинарный файл который надо прочитать: https://drive.google.com/file/d/0B7zD9kDjFhBzd1VUVG8tbzdMb1lEWXBoWnlWTUhpbVFmZ18w/view?usp=sharing

Снизу приведена моя реализация решения.

Насколько я понял в файле только 2 человека, после того как я вывожу информацию о 2, программа перестает адекватно работать, то есть при вводе команд информация больше не выводится. Как я заметил при отладке переменная idSize, которая отвечает за размер выводимого блока информации, при последующих вызовах всегда равно 0, соответственно ничего и не выводится - логично, но тем не менее я не могу понять почему ей перестают присваиваться значения из бинарного файла.

#include "pch.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int select(char var, ifstream &fin, string path, int numPers) {
    cout << "numPers = " << numPers << endl;
    if (var == 'e') { // закрытие программы командой "e"
        fin.close();
    }
    else {
        int intVar = var - '0'; // приведение команды типа char к int 
        cout << "intVar = " << intVar << endl;
        int bytePos = 1; // Положение указателя чтения из файла
        fin.seekg(bytePos);
        int currentPos = 1; // Идентификатор текущего пользователя 
        if (intVar > numPers) {  // Если ведено число больше кол-ва людей в файле , вывод сообщения что информации нет.
            cout << "There are no information under this ID." << endl;
            return 0;
        }
        else {
            while (currentPos != intVar) { // Пока текущее id не равно запрашиваемому выполняется алгоритм 
                bytePos++;                  //который исчет 1 байт информации соответсвующего ID и сохраняет его в  bytePos
                fin.seekg(bytePos);
                int lastSize = 0; // Размер последнего выведенного блока 
                fin.read((char*)&lastSize, 1);
                cout << "lastSize =" << lastSize << "   "; // эти выводы необязательны, использовал для себя , для вывода промежуточной информации при отладке
                bytePos = bytePos + lastSize + 1;
                cout << "bytePos =" << bytePos << "   ";
                fin.seekg(bytePos);
                currentPos++;
                cout << "currentPos =" << currentPos << endl;
            }
        }
        bytePos += 3; // перемещаем еще на 3 байта чтобы перейти к самой информации 
        for (int k = 0; k < 6; k++) { // Алгоритм вывода соответвующей информации в зависимости от типа данных 
            fin.seekg(bytePos);  //состоит из 6 иттераций так как 6 блоков информации
            cout << "bytePos =" << bytePos << endl;// определяет размер каждого блока 
            int idSize = 0;
            fin.read((char*)&idSize, 1);
            cout << "idSize =" << idSize << endl;
            if (idSize == 0) { // Если блок пропущен , переходит к следующему
                bytePos += 2;
                continue;
            }
            char* name = new char[idSize]; //  Использую динамический массив char, длина которого равно значению байта, который отвечает за длину блока информации
            int nameInt =0;
            if (k == 3 || k==5) {  // для блоков 3 и 5 которые численного типа использую другой обработчик информации 
                bytePos++;
                fin.seekg(bytePos);
                fin.read((char*)&nameInt, idSize);
                    cout << " " << nameInt << " ";
            }
            else { // для блоков типа char
                bytePos++;
                fin.seekg(bytePos);
                fin.read((char*)name, idSize);
                for (int j = 0; j < idSize; j++) {
                    cout << name[j];
                }
            }
            bytePos += idSize + 1;
        }
    }
    cout << "Works";
}
int main()
{
    string path = "UserData.bin";
    ifstream fin;
    fin.open(path);
    if (fin.is_open())
    {
        cout << "All is good!" << endl;
        cout << "Enter comand:" << endl;
        char var; // id запрашиваемого человек
        bool checkComand; // проверка на допустимую команду 
        char arrayComand[11] = {'0','1','2','3','4','5','6','7','8','9','e'};
        int numPers = 0; // Кол-во человек в списке
        fin.seekg(0);
        fin.read((char*)&numPers, 1);
        while (fin.is_open()) {  // пока открыт файл, читаю команды с клавиатуры 
            cin >> var;
            if (var == 'E') var = 'e';
            for (int i = 0; i < 11; i++) {
                if (var == arrayComand[i]) {
                    select(var, fin, path , numPers); // функция выводы информации запрашиваемому человеку
                    checkComand = true; 
                    break;
                }
            }
            if (!checkComand) continue;
        }
    }
    else
    {
        cout << "Error: it's not working :(";
    }
    fin.close();
}
Answer 1

Вам стоит определиться, что именно вы должны получить после разбора файла (какая получится структура данных), разбить процесс разбора на части и сформировать эту структуру. Использование полученной структуры - это уже другая задача. Если разделить задачу на части, найти ошибку будет куда проще.

Ну и использование стандартной библиотеки сильно облегчает жизнь.

Я бы сделал примерно так (концептуально, тут могут быть ошибки):

using namespace std;
using byte = char; // В C++17 есть нормальный std::byte
struct User{
    byte id;
    map<byte, vector<byte>> dataSet; // Предполагаю, что идентификатор не повторяются
};
User parseUser(std::iostream& in){
    User user;
    in.read(&user.id, 1);
    if(!in){
        // error
    }
    byte blockSize;
    in.read(&blockSize, 1);
    int signedBlockSize = blockSize;
    while(signedBlockSize > 0){
        // читаем id, читаем размер данных, читаем данные. Не забываем уменьшать signedBlockSize 
    }
}
vector<User> parseFile(std::iostream& in){
    vector<User> ret;
    byte usersCount;
    in.read(&usersCount, 1);
    if(!in){
        // error
    }
    for(int i = 0; i < usersCount; ++i){
        ret.push_back(parseUser(in));
    }
    return ret;
}

Как минимум, тут еще нужно обрабатывать ошибки чтения файла и ошибки формата пакета, но для вашей задачи это может быть не важно.

Дальше с этой структурой уже можно делать что угодно, например, искать пользователей по id (но тогда лучше положить их в map, а не в vector) - но если вы при этом допустите ошибку, в отладчике вы скорее всего увидите, что ошибка не в парсинге файла, а в интерпретации структуры. Ну или наоборот.

READ ALSO
Сортировка multiset

Сортировка multiset

Есть multiset<multiset<int>> cnt; Хочу отсортировать cnt по последнему элементу multiset-овКак это сделать?

130
Visual Studio выдаёт ошибку C4996 при попытке скомпилировать этот проект

Visual Studio выдаёт ошибку C4996 при попытке скомпилировать этот проект

В Visual C++ рекомендуется использовать функцию strcat_s, и другие функции с _s на концеОна принимает размер буфера, по этому при ее использовании...

116
Как найти квадрат в двумерном массиве?

Как найти квадрат в двумерном массиве?

Нашел задачу на двумерный массив и не понятно как код писать, сам недавно начал учит с++

187
Реализация ассемблерной вставки [закрыт]

Реализация ассемблерной вставки [закрыт]

Найти сумму положительных элементов массива A = {a [i]}, что удовлетворяют условию: b <= a [i] <= dНаписал код но не могу понять почему оно не работает...

117