Reading Binary File in C++

Asked

Viewed 1,571 times

1

Good morning.

I’m trying to make a read of structs that I inserted in a binary file, but is giving error at the time of reading.

Follow the code of the reading function:

void lerRegistros(char* file_name)
{
    ifstream entrada;
    entrada.open(file_name, ios::binary);

    if ( entrada )
    {
        entrada.seekg(0, entrada.end);
        int tam = entrada.tellg();
        entrada.seekg(0, entrada.beg);

        int numero_registros = tam / sizeof(registro);

        registro* vetor_registros = new registro[numero_registros];

        for (int i = 0; i < numero_registros; i++) 
        {
            entrada.read((char*)(&vetor_registros[i]), sizeof(registro));         
        }

        entrada.close();

        for ( int i = 0; i < numero_registros; ++i )
        {   
            cout << "Nome da banda: " << vetor_registros[i].nome << endl;
            cout << "Numero de integrantes: " << vetor_registros[i].numero_integrantes << endl;
            cout << "Estilo: " << vetor_registros[i].estilo << endl;
            cout << "Ano de criacao: " << vetor_registros[i].ano_criacao << endl;
            cout << "Melhor hit: " << vetor_registros[i].musica_famosa << endl;
            cout << endl;
        }

        vetor_registros = NULL;
        delete[] vetor_registros;
    }
    else
    {
        cout << "Erro na leitura do arquivo!";
    }

    return;
}

In the program, I ask the file name to read the records and pass this name to the reading function. The strange thing is that if I run the program without closing it, the reading is usually done after each insertion of a new record. But if I close the program and open it again, and try to read from the same file that was already created there gives error in reading and the program closes on time. If anyone knows what it might be, I’d appreciate it.

Follows the definition of the structure:

struct banda_rock 
{
    string nome;
    int numero_integrantes;
    string estilo;
    int ano_criacao;
    string musica_famosa;
};

And below follows the code that writes to the file and calls the function "lerRegistros". In the "lerRegistros" function, I put a "record" vector, but it was just to simplify the code, it’s actually a "banda_rock" vector, which is the struct type name I created.

int quant = 0;
char* file_name;

banda_rock* ptrcatalogo;

cout << endl << "Digite a quantidade de bandas : ";
cin >> quant;

file_name = new char[100];

cout << "Digite o nome do arquivo a ser armazenado as bandas (com o extensao) : ";
cin >> file_name;
cin.ignore();

ptrcatalogo = new banda_rock[quant];

ofstream salvar_bandas; 
salvar_bandas.open(file_name, ios::binary|ios::app);

inserir_cadastro(quant, ptrcatalogo);

for (int i = 0; i < quant; i++) 
{
    salvar_bandas.write(reinterpret_cast<const char*> (&ptrcatalogo[i]), sizeof(banda_rock));                 
}

ptrcatalogo = NULL;
delete[] ptrcatalogo;

salvar_bandas.close();

lerRegistros(file_name);

file_name = NULL;
delete file_name;
  • Gives error in reading and runs the Cout "Error in reading file"? It may have nothing to do with it but have you ever thought about changing if(input) to if(input.good()) ? I usually test this way.

  • It does not even display the Cout "Error in reading the file". The execution of the program ends before, it shows the text "Band name: " and then gives the error. I will test with this condition in the if you spoke. Thanks!

  • Also put the structure/class definition registro as well as an example of the file you are trying to read, so it is easy to reproduce the problem.

  • Now that I noticed! Are you reading the block directly in the structure, alias, is it a structure or a class? How is its definition? I already say that if the field "name" is string it is certain that will give problem. (-:

  • That is, it’s a real structure. The "name" field is a string and has two other fields in the structure that are string. I don’t understand why it is a problem if it is xD string. I will post the structure definition and the code you write to the file.

  • I edited the question by asking what you asked for. If you could take a look, I would really appreciate it.

  • @Muriloaugustoteixeirabiagi in writing you are converting from a direct struct to a char pointer, probably the file is already recording corrupted.

  • The problem is that the write function takes a char* as the first argument, so I need to cast a char* of my struct at the time of recording.

Show 3 more comments

2 answers

1

Note:

I wrote a code based on what you said, that I wanted the code to do. to better demonstrate the response in terms of C functionalities++.

Details:

You said you’re programming in C++ but is using a style similar to C not that it’s wrong, but, for example, there’s no need to use Naked pointers to manipulate the struct you created, or pass a const char* to the reading function, but that’s not the case with the question, what I wanted to tell you with this is for you to study the "features" that language offers you, rather than trying to do the old-fashioned way.

Answer:

I believe that in your code what is wrong in the reading function, is the use of read the way you used,

input.read((char*)(&vector_records[i]), sizeof(record));

And also after the loop is in which you display the data, you are setting vector_recordsas NULL before deleting it:

vector_records = NULL;
delete[] vector_records;

where the right one would be:

delete [] vector_records; vector_records = nullptr;

Code:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

struct banda_rock 
{
    std::string nome;
    int numero_integrantes;
    std::string estilo;
    int ano_criacao;
    std::string musica_famosa;
};

bool write( const std::string& file_name, const std::vector<banda_rock>& v_registers ); 
std::vector< banda_rock > read( const std::string& file_name );
void insert( const size_t& num_registers, std::vector<banda_rock>& v_registers );

int main()
{ 
    //quant deve ser size_t por que já que você tem a intenção de expressar a
    //quantidade de algo, e essa quantidade não pode ser negativa
    //(size_t só aceita valores positivos e o 0( no seu caso você não precisa do 0) )
    size_t quant = 0;
    std::string file_name;
    std::vector< banda_rock > v_catalogo;


    //Caso o que a pessoa digite não seja um número ou um numero menor que zero
    if( quant == 0 )
    {
        std::cout << "\nDigite a quantidade de bandas : ";
        std::cin >> quant; 
        while( std::cin.fail() )
        { 
            std::cin.clear( std::ios::goodbit );
            std::cin.ignore(); 
            std::cin >> quant; 

        }
    }
    if( quant > 0 )
    {
        std::cout << "Digite o nome do arquivo a ser armazenado as bandas (com a extensao) : ";
        std::cin >> file_name; 
        while( std::cin.fail() )
        { 
            std::cin.clear( std::ios::goodbit );
            std::cin.ignore(); 
            std::cin >> file_name;
        }
    }       


    //chama a função que vai popular o vetor
    insert( quant, v_catalogo );

    //escreve  arquivo
    if( write( file_name, v_catalogo ) )
    {
        //se a operação de escrita obteve sucesso
        v_catalogo.clear();
        v_catalogo.shrink_to_fit();
        v_catalogo = read( file_name );
    }
    else{ std::cout << "\nNão foi possivel escrever no arquivo." << std::endl; }

    for ( size_t i = 0; i < v_catalogo.size(); i++) 
    {
        std::cout << "\tNome: " << v_catalogo[ i ].nome << '\n' 
                  << "\tIntegrantes: " << v_catalogo[ i ].numero_integrantes << '\n' 
                  << "\tEstilo: " << v_catalogo[ i ].estilo << '\n'
                  << "\tAno de criação: " << v_catalogo[ i ].ano_criacao << '\n'
                  << "\tMúsica Famosa: " << v_catalogo[ i ].musica_famosa << "\n\n";
    }

    return 0;
}

bool write( const std::string& file_name, const std::vector<banda_rock>& v_registers )
{
    if( v_registers.empty() ){ return false; }

    std::ofstream out; 
    out.open( file_name, std::ios::binary|std::ios::app );
    if( !out.is_open() ){ out.close(); return false; }
    else
    {
        for ( size_t i = 0; i < v_registers.size(); i++) 
        {
            //o # pode servir para posteriormente para você contar quantos 
            //registros você têm (fica a seu critério usá-lo ou não)
            out << '#' << ' ' 
                << v_registers[ i ].nome << ' ' 
                << v_registers[ i ].numero_integrantes << ' ' 
                << v_registers[ i ].estilo << ' '
                << v_registers[ i ].ano_criacao << ' '
                << v_registers[ i ].musica_famosa << '\n';            
        }
    }

    out.close();
    return true;
}

std::vector< banda_rock > read( const std::string& file_name )
{
    std::ifstream in;
    size_t quant = 0;
    char ch_aux;

    in.open(file_name, std::ios::binary);
    if ( !in.is_open() ){ in.close(); }
    else
    {
        while( !in.eof() )
        {
            in.get( ch_aux );
            if( ch_aux == '#' ){ quant++; }
        }
    }    
    in.close();

    std::vector<banda_rock> v_registers;
    v_registers.resize( quant );

    in.open(file_name, std::ios::binary);
    if ( !in.is_open() ){ in.close(); }
    else
    {
        for( size_t i = 0; i < v_registers.size(); i++ )
        {
                in.ignore( 1, '#' );
                in >> v_registers[ i ].nome 
                   >> v_registers[ i ].numero_integrantes
                   >> v_registers[ i ].estilo
                   >> v_registers[ i ].ano_criacao
                   >> v_registers[ i ].musica_famosa;
        } 
    }    
    in.close();

    return v_registers;

}

void insert( const size_t& num_registers, std::vector<banda_rock>& v_registers )
{
    v_registers.resize( num_registers );

    std::cout << "insira os dados da banda:" << std::endl;
    for( size_t i = 0; i < v_registers.size(); i++ )
    {
        std::cout << " Nome da banda [" << i + 1 << "]: ";
        std::cin >> v_registers[ i ].nome;
        while( std::cin.fail() )
        { 
            std::cout << "\tpor favor digite o nome da banda [" << i + 1 << "]." << std::endl;
            std::cin.clear( std::ios::goodbit ); 
            std::cin.ignore();  
            std::cin >> v_registers[ i ].nome;
        }

        std::cout << " Número de integrantes da banda [" << i + 1 << "]: ";
        std::cin >> v_registers[ i ].numero_integrantes;
        while( std::cin.fail() )
        { 
            std::cout << "\tpor favor digite o número de integrantes da banda [" << i + 1 << "]." << std::endl; 
            std::cin.clear( std::ios::goodbit ); 
            std::cin.ignore(); 
            std::cin >> v_registers[ i ].numero_integrantes;
        }

        std::cout << " Estilo da banda [" << i + 1 << "]: ";
        std::cin >> v_registers[ i ].estilo;
        while( std::cin.fail() )
        { 
            std::cout << "\tpor favor digite o estilo da banda [" << i + 1 << "].";                                     
            std::cin.clear( std::ios::goodbit ); 
            std::cin.ignore();
            std::cin >> v_registers[ i ].estilo;
        }

        std::cout << " Ano de criação da banda [" << i + 1 << "]: ";
        std::cin >> v_registers[ i ].ano_criacao;
        while( std::cin.fail() )
        { 
            std::cout << "\tpor favor digite o ano de criação da banda [" << i + 1 << "]."; 
            std::cin.clear( std::ios::goodbit ); 
            std::cin.ignore(); 
            std::cin >> v_registers[ i ].ano_criacao;
        }

        std::cout << " Musica Conhecida da banda[" << i + 1 << "]: ";
        std::cin >> v_registers[ i ].musica_famosa;
        while( std::cin.fail() )
        { 
            std::cout << "\tpor favor digite uma música conhecida da banda [" << i + 1 << "].";
            std::cin.clear( std::ios::goodbit );  
            std::cin.ignore(); 
            std::cin >> v_registers[ i ].musica_famosa;
        }

    }
}
  • Thank you very much! The tips were very useful and I used your code as a basis to fix mine. This form of reading in the file with the ">>" is much more practical than using the "read" function. And I changed the way I dislocated the pointer memory, I was really wrong. The program now works if the strings have a single word. If I put a band name composed for example, at the time of reading it only brings the first name of the band, in the field of the members it brings 0, the year it brings correct and the known music brings blank. Whatever is causing this ?

  • Just one more detail, the file I write and read in is binary (.dat)

  • about the format of the I believe that does not change much, what you commented about reading only the first word of the band is because you this Std::Cin for reading and he reads this way, I suggest that you use Std::getline(), take a look at this link to understand better how it works. http://www.cplusplus.com/reference/string/string/getline/

  • Thanks!! with getline() it worked, now it was.

  • Do not forget that you still have a problem to solve which is reading the data that are with composite names into your structure. Now as a suggestion, I don’t think that’s the best way to do it (of course that’s up to you). For example, you could use a database for this, or as a faster solution Voce could use an xml file

0

You have the following problem: In c++ binary files do not accept dynamic variables like strings and vector. You need to read/write the file as an array of char, for this use the function reinterpret_cast:

arquivo.write(reinterpret_cast  <const char *> 
(&variavel),sizeof(tipo_dado_variavel))


arquivo.read(reinterpret_cast<char *> (&variavel),
sizeof(tipo_dado_variavel))

*The operator >> does not work for binary streams, has to be arquivo.read/write even.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.