binary fstream read/write - string issues?

Hello again code monkeys, code lemurs, and coders of all species. My training has once again brought me to beg for help as I cannot see the flaw of my ways.

This is a program to write to a file in binary, apparently keeping the same format per record to create a random access capable file. The book I'm using seems to be slightly older, and taught about the char strings and then about string class strings, and leaned us toward the latter (for obvious reasons) but then continued to write all the examples using char type. I've thus adapted my code based on help I've received here earlier to convert the string types using c_str() which in this case I'm pretty sure I did right(pls let me know if not).

the error I'm getting here is that if statement on line 24 keeps evaluating as true and returning the file error. I know that the program needs admin access and the file needs to not be read only (both of which are not the case here) why else would I get this error?

Please also note that on line 40 the write function is using reinterpret_cast<char*> (apparently for record size consistency?) it makes sense but since all of my other strings are string class types does this cause an issue? I feel like this section of the book may be a little complex for what I've learned so far but I do enjoy the challenge! Thanks in advance for your help!!

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
#include <iostream>
#include <fstream>
#include <string>
#include <string.h>
#include <stdlib.h>

using namespace std;

int getint(int defval);
string name;

int main()
{
    string filename;
    int n;
    int age;
    int recsize = sizeof(name) + sizeof(int);

    cout << "\n\nEnter filename: ";
    getline(cin, filename);

    fstream binfile(filename, ios::binary | ios::in | ios::out);

    if(! binfile)
    {
        cout << "\n\n could not open file: " << filename;
        return -1;
    }

    cout << "\n\nEnter file record number; ";
    n = getint(0);

    cout << "\n\n Enter name: ";
    getline(cin, name);
    cout << "\n\nEnter age: ";
    age = getint(0);

    binfile.seekp(n * recsize);
    binfile.write(name.c_str(), 20);
    binfile.write(reinterpret_cast<char*>(&age), sizeof(int));
    binfile.close();

    return 0;
}


int getint(int defval)
{
    string s;
    getline(cin, s);

    if(strlen(s.c_str()) == 0)
    {
        return defval;
    }

    return atoi(s.c_str());
}
the error I'm getting here is that if statement on line 24 keeps evaluating as true and returning the file error.


Opening a file with ios::in will fail unless the file already exists. It will not create a new file if the file is not already there.

This is extremely likely that this is what is happening for you. If the file is there, make sure you are inputting the file name properly (extension included) and make sure the file is in the correct path. Having the file in the wrong path is another common mistake.

int recsize = sizeof(name) + sizeof(int);

This does not do what you think it does. sizeof(name) will give you the size of the std::string class, which is completely meaningless for your purposes.

This line probably made sense if 'name' was a char array. But it simply does not translate to strings.


if(strlen(s.c_str()) == 0)

While this will work, it's extremely roundabout and kind of silly. You're converting the string to a char array... just so you can use a char function. Instead, you could just use the string functions (which will undoubtedly be faster). Alternatives are:

1
2
3
if( s.empty() ) // <- best
//
if( s.length() == 0 ) // <- still better than strlen 



 
binfile.write(name.c_str(), 20);


This will only work if 'name' is at least 19 characters long. You never guarantee that. So it's possible this is accessing out of bounds memory which may lead to strange behavior and/or program crash (though it's unlikely).






You are correct that std::string should be preferred over char arrays in most instances. However... for this particular project -- where you are doing naive dumps of string data to a binary file.... this is one of the very few instances where fixed-length char arrays make the job easier.

It's clear this assignment was designed to have 'name' be no larger than 20 characters, and for it to dump a fixed-length array to the file. That is more difficult to accomplish with strings which allocate memory dynamically and can have a variable length.
Last edited on
You are absolutely correct and thanks a bunch. The main problem I was having there is that the file does not already exist and the book makes no mention of this necessity. In the previous exercise we created text files with the same stream and it did create the file so I'm not sure where I was supposed to pick up the fact that it doesn't work for binary seeing as how the book makes no mention of any of this and I'm not even totally sure what extension to use to create said file so that I can access it with this program...

I had the assumption (based on the fact that char types are fixed length) that they were required for this and that it would kind of fall apart with strings, part of me is just bothered by the fact that they spent an entire chapter touting the string class and saying we would rarely ever use char and then proceed to use it in every example. I'm feeling like I may need to look into a more up to date book as I'm sure there are ways to create a file like this without the use of char.

I'm also not fully seeing the value of this exercise especially considering how tedious and annoying it is lol. Maybe someone can shed some better light on the subject than my book has.
Binary file I/O is usually taught very poorly. And for what it's worth, you're usually better off doing text I/O anyway.

If you really want to learn how binary I/O works... the only way to truly understand it is to get a hex editor. I recommend HxD -- it's a free hex editor that is very polished and works well.

Write some data to a binary file... then open the file with a hex editor to see how it actually looks in the file. That's the only way to really "get it". Until you do that, it'll just seem like black magic.

I also wrote some forum posts about it that people transcribed to articles. If you want to learn more, they're worth a read:
http://www.cplusplus.com/articles/DzywvCM9/
http://www.cplusplus.com/articles/oyhv0pDG/


EDIT:

In the previous exercise we created text files with the same stream and it did create the file so I'm not sure where I was supposed to pick up the fact that it doesn't work for binary


Text/binary has nothing to do with it. It's the ios::in flag. If you are using that flag, the file must exist.

When you were creating text files before... you must not have been using that flag.
Last edited on
*bows* Thanks a million for these articles I cant wait to see what it looks like with a hex editor. Also, you're right. we didn't use the flag in the other examples. Does this mean I could just remove the flag and it would create the file for me or does that cause some other complication? I'm going to try it anyway. Over 12k posts and still helping noobs, I am humbled, Thanks again!

Edit: These articles are awesome. If you do happen to have time for another reply here, the only thing I feel like I'm missing is the point of said binary files. Why would I use these? My book also seems to gloss over this fact which automatically makes me question whether this is more of a hardcore archaic method to save tiny amounts of space or something.
Last edited on
Also, you're right. we didn't use the flag in the other examples. Does this mean I could just remove the flag and it would create the file for me or does that cause some other complication?


It would create the file, but then it would be write-only. You couldn't read.

the only thing I feel like I'm missing is the point of said binary files. Why would I use these?


Binary files are great at storing large clumps of data in a space efficient manner. Most complex data files you're used to dealing with which are "data heavy" are binary files (zip, mp3, jpg, png, the list goes on), not only because it's a large 'clump' of data, but also because file size is an issue.

Text files are bigger and not really as efficient, but they have the tradeoff of being easier to work with. Anyone can open an xml,html,css,txt, etc file in any text editor and immediately see the contents of the file in a reasonably informative way. Text files are also usually more expandable (or.. at least are easier to make expandable)


For what you're doing... which is relatively small amounts of data that does not need to be super space efficient... text files are almost definitely the right decision.

A very general guideline is... if the file is compressed, or is little more than a big dump of a block of memory... then you want a binary file. Otherwise, you probably want a text file. Of course, there are always exceptions. Use your judgement.


Thanks again!


I'm happy to help.
Seeing you list those file types makes much more sense as to what a binary file is. I can see how they can be compressed and why it works with binary just from what I know about binary and hexadecimal. Also seeing it in this light justifies not skipping it in my book haha clearly it's more useful than I had realized from that lack on information they gave me before stuffing it in my face.
Topic archived. No new replies allowed.