reading from file question

Hi there

I am learning now about reading and writing to a file, there is something i don't understand.

when I try to read names back I have set loop for that goes in my case from 0 to 12 (as there is 12 names in file Group.dat)
with an arrays you are increasing number in the loop for example

1
2
3
4
for (int i = 0; i < 10; i++)
{
      cout << array[i] << endl;
}


however, with reading file I have this:
1
2
3
4
5
6
inFile.seekg(0);
    for (int i = 0; i < n ; i++) {
        inFile.read(reinterpret_cast<char*>(&person), sizeof(person));
        person.showData();
        std::cout << std::endl;
    }


does this means that
inFile.seekg(0); put us at the start of the file?
but how file is iterated later? What is causing to print another record from file not same record 12 times?


thanks :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <fstream>                                          //for file stream
class Person
{
protected:
    char name[80];                                          // person name
    short age;                                              // person age
public:
    void getData()                                          // get person data
    {
        std::cout << "Enter name: ";
        std::cin >> name;
        std::cout << "Enter age: ";
        std::cin >> age;
    }
    void showData()
    {
        std::cout << " Name: " << name;
        std::cout << " Age: " << age;
    }
};

int main() {

    Person person;                                              // create person
    std::ifstream inFile;                                       // create input output file
    inFile.open("Group.dat", std::ios::in | std::ios::binary);  // open file
    inFile.seekg(0, std::ios::end);                             // go to 0 bytes from end
    int endposition = inFile.tellg();                           //find where we are
    int n = endposition /sizeof(person);                        // number of persons
    std::cout << "There are " << n << " persons in file" << std::endl;


    //inFile.read(reinterpret_cast<char*>(&person), sizeof(person));

    inFile.seekg(0);
    for (int i = 0; i < n ; i++) {
        inFile.read(reinterpret_cast<char*>(&person), sizeof(person));
        person.showData();
        std::cout << std::endl;
    }

   
    std::cout << std::endl;

    std::cin.get();
    return 0;
Last edited on
The position is automatically updated by the read function.
Hi Peter87

thanks, so does this work like in a loop with steps?
First time it reads file it goes the size of person object (which is 82 bytes)
then goes to the next person?
xxvms wrote:
thanks, so does this work like in a loop with steps?
First time it reads file it goes the size of person object (which is 82 bytes)
then goes to the next person?

The loop reads a number of bytes equal to the value of “sizeof(person)” at every iteration, starting from the byte in file following the last reading operation.
I can’t know what you supposed it should do, but I suspect you assume your code perform operation it doesn’t do.

Have you tested it? Assuming you have got a group.dat file like this:
Danielle Brown 20
Lindsey Carmichael 21
Miroslava Cerna 22
Mel Clarke 23
Gizem Girismen 24
Fu Hongzhi 25
Gao Fangxia 26
Kim Ki Hee 27
Kim Ran Sook 28
Lenka Kuncova 29
Malgorzata Olejnik 30
Lee Hwa Sook 31
Marketa Sidkova 32
Xiao Yanhong 33

your output will be:
There are 3 persons in file
 Name: Danielle Brown 20
Lindsey Carmichael 21
Miroslava Cerna 22
Mel Clarke 23
Gizem Age: 28005
 Name:  Girismen 24
Fu Hongzhi 25
Gao Fangxia 26
Kim Ki Hee 27
Kim Ran Sook 28
Lenka Age: 24939
 Name:  Kuncova 29
Malgorzata Olejnik 30
Lee Hwa Sook 31
Marketa Sidkova 32
Xiao Yanh Age: 26734

As you can see, data are wrong, but the problem is not your reading procedure.

std::basic_istream::read(char_type* s, std::streamsize count) stores “count” characters inside “s”.
Passing the reference to a class instead of a “char*” and then trying to “reinterpret_cast” it means playing a dirty trick which doesn’t happen to work.
I may agree that a pointer to a class in all likelihood is a pointer to the memory area where its properties are stored, but you can’t take it for granted, not even if there aren’t static variables.
Your code could have a chance to work if every line of the file were long exactly 80*sizeof(char) + sizeof(person).
This because in some machine it could be that your char name[80]; and short age; were stored in adjacent memory cells. But I think there’s a subtle difference between gambling and programming.

BTW, you should consider that you don’t know which is the size of 80*sizeof(char) + sizeof(person) because the size of “short int” is not guarantee to be 16 bits, but *at least* 16 bits:
http://en.cppreference.com/w/cpp/language/types
It means it’s machine-dependent.
Hi Enoizat

that is amazing :)
I am following example from my book, and trying to understand this.
in this chapter they use pretty much in every example

inFile.read(reinterpret_cast<char*>(&person), sizeof(person))

I was wondering (with my limited understanding of C++) is that best way of doing it??
why would you cast char, I was thinking you could read this by way of reading type person (like with overloaded operators where you know that type person is char and sort)

I think I am not impressed with this chapter in the book
Do you know by any chance any good tutorial about Stream and Files?

thanks :)
inFile.read(reinterpret_cast<char*>(&person), sizeof(person))

I’m just a C++ beginner, so it’s possible that the authors know something I ignore, but I can’t figure out what it could be. Anyway, if you test the code, it doesn’t work properly.

you could read this by way of reading type person (like with overloaded operators where you know that type person is char and sort)

It sounds far better and clearer to me.

Do you know by any chance any good tutorial about Stream and Files?

I don’t, I’m sorry. I’m one of those persons who learns by trials and errors and I would be able to find only the same tutorials you could find on your own just browsing on internet.
If you really plan to delve into files management in C++, I can only share with you my limited experience by suggesting:
a) trying to find something written recently.
The new standard, C++17, is going to add an entire new library related to files and filesystem and old tutorials would probably not discuss it:
http://en.cppreference.com/w/cpp/experimental/fs

b) Spending some time with less used features, like file exceptions:
http://en.cppreference.com/w/cpp/io/basic_ios/exceptions
Even if the classical “is_open()” is usually good enough to guarantee our data will be saved, the day you need to write a robust professional code perhaps you decide you want your fstreams to throw exceptions.

c) Remembering in... how to say? “real life programming” :-) ...the fastest and most comfortable way to save data is by databases.
So I think the majority of people use ‘traditional’ files only for text.

What’s above is just a personal opinion, somebody else could offer a you totally different view!
Last edited on
Hi Enoziat
Interesting :) you have fair bit of knowledge as for beginner 😁😁😁

I just wonder how much time should I spent on stuff and as you pointed out in real life situation you would be saving your stuff to database not a local file.

Maybe someone with more experience would voice his opinion on this.

Thank you for your input
Since you're trying to read() the file in binary mode you must first write() the file in binary mode. A file written with the write() function is not considered "human readable" and if you try to view the file with a text editor it will appear to have a bunch of random garbage. You need to view a binary file with a hex editor in order to view the contents.

Here is a small sample of writing then reading a binary file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>
#include <cstring>
#include <iomanip>

using namespace std;

struct Person
{
    char first_name[40];
    char last_name[40];
    int age;
    Person() = default;
    Person(char *fname, char* lname, int age) : age(age)
    {
        // Insure strcpy doesn't overflow array size.
        if(strlen(fname) >= sizeof(first_name))
            throw("First Name too long.");

        if(strlen(lname) >= sizeof(last_name))
            throw("Last Name too long.");

        strcpy(first_name, fname);
        strcpy(last_name, lname);

    }
};

int main()
{
    stringstream sin("Danielle Brown 20\nLindsey Carmichael 21\n"
                     "Miroslava Cerna 22\nMel Clarke 23\n"
                     "Gizem Girismen 24\nFu Hongzhi 25\n");


    std::ofstream fout("data.dat", std::ios::binary);

    if(!fout)
        return 1;

    char first_name[40];
    char last_name[40];
    int age;

    try
    {
        // Read the stringstream contents, be sure to limit the number of characters
        // the extraction operator will try to retrieve using the setw() manipulator.
        while(sin >> setw(40) >> first_name >> setw(40) >> last_name >> age)
        {
            // Create a temporary instance of the structure with the values read above.
            Person temp{first_name, last_name, age};
            // Now write the structure to the file using write().
            fout.write(reinterpret_cast<char*>(&temp), sizeof(temp));
        }
    }
    catch(const char* e)
    {
        std::cerr << e << std::endl;
        return 3;
    }

    // Close the file so it can be reopened for input.
    fout.close();

    // Now let's read the file back to verify the contents.
    std::ifstream fin("data.dat", std::ios::binary);

    if(!fin)
        return 2;

    Person from_file;

    while(fin.read(reinterpret_cast<char*>(&from_file), sizeof(from_file)))
        std::cout << from_file.first_name << " " << from_file.last_name << " " << from_file.age << std::endl;

}





Hi JLB

thanks for that :) I will sit down and analyze this later :)


once again thank you :)
in this chapter they use pretty much in every example

inFile.read(reinterpret_cast<char*>(&person), sizeof(person))

I was wondering (with my limited understanding of C++) is that best way of doing it??

It can be more complicated depending on the content of each Person:

https://isocpp.org/wiki/faq/serialization
Last edited on
> I was wondering (with my limited understanding of C++) is that best way of doing it?

No.

The primary model for output in C and C++ is to convert the internal representation of an object into a sequence of human readable characters. Correspondingly, input is the conversion of a sequence of human readable characters into the internal representation of an object. The designers of the C/C++ standard libraries got that right from the outset - they emphasied the importance of being textual. Everything that has happened later - HTTP, PNG, XML, SOAP, REST, JSON ... - all provide evidence of the validity of that design decision.

ESR on the importance of being textual:
Interoperability, transparency, extensibility, and storage or transaction economy: these are the important themes in designing file formats and application protocols. Interoperability and transparency demand that we focus such designs on clean data representations, rather than putting convenience of implementation or highest possible performance first. Extensibility also favors textual protocols, since binary ones are often harder to extend or subset cleanly. Transaction economy sometimes pushes in the opposite direction — but we shall see that putting that criterion first is a form of premature optimization that it is often wise to resist. ...
...
When you feel the urge to design a complex binary file format, or a complex binary application protocol, it is generally wise to lie down until the feeling passes. ...
...
Designing a textual protocol tends to future-proof your system. ...

http://www.faqs.org/docs/artu/textualitychapter.html

You may want to read the whole chapter.
You may want to read the whole chapter.

It is actually a good book -- maybe read the whole book?
Topic archived. No new replies allowed.