does fstream move to the next position after read in a binary integer (c++) - c++

I am trying to read in a binary file and write in chunks to multiple output files. Say if there are 25 4byte numbers in total and chunk size is set to 20, the program will generate two output files one with 20 integers the other with 5. However if I have a input file with 40 integers, my program generates three files, first 2 files both have 20 numbers, however the third file has one number which is the last one from the input file and it is already included in the second output file. How do I force the read position to move forward every time reading a number?
ifstream fin("in.txt", ios::in | ios::binary);
if(fin.is_open())
{
while(!fin.eof()){
//set file name for each output file
fname[0] = 0;
strcpy(fname, "binary_chunk");
index[0] = 0;
sprintf(index, "%d", fcount);
strcat(fname, index);
// open output file to write
fout.open(fname);
for(i = 0; i < chunk; i++)
{
fin.read((char *)(&num), INT_SIZE);
fout << num << "\n";
if(fin.eof())
{
fout.close();
fin.close();
return;
}
}
fcount ++;
fout.close();
}
fout.close();
}

The problem is most likely your use of while (!fin.eof()). The eofbit flag is not set until after you have tried to read from beyond the end of the file. This means that the loop will loop one extra time without you noticing.
Instead you should remember that all input operations returns the stream object, and that stream objects can be used as boolean conditions. That means you can do like this:
while (fin.read(...))
This is safe from the problems with looping while !fin.eof().
And to answer your question in the title: Yes, the file position is moved when you successfully read anything. If you read X bytes, the read-position will be moved forward X bytes as well.

Related

how can i write an array of structures to a binary file and read it again?

I'm writing an array af structures(factor is a structure) to a binary file like this:
factor factors[100];
ofstream fa("Desktop:\\fa.dat", ios::out | ios::binary);
fa.write(reinterpret_cast<const char*>(&factors),sizeof(factors));
fa.close();
and I run the program and save 5 records in it.in another file, I want to read the structures so I wrote this:
int i=0;
ifstream a("Desktop:\\fa.dat", ios::in | ios::binary);
factor undelivered_Factors[100];
while(a && !a.eof()){
a.read(reinterpret_cast<char*>(&undelivered_Factors),sizeof(undelivered_Factors));
cout<<undelivered_Factors[i].ID<<"\t"<<undelivered_Factors[i].total_price<<endl;
i++;
}
a.close();
but after reading and printing the saved factors it inly reads and shows the firs 2 of them in the array.why?what should i do?
Second parameter of ofstream::write and ::read is size of written memory in bytes (aka 'char' in C\C++), which is right - you're writing entire array at once. In reading procedure you had mixed up an per element and array processing. You expect to read whole array, then you print one value, then you read another 100 of records which you do not have in file, I presume. also eof() happens only when you attempt to read and it failed. If you stand on end of file,eof() isn't triggered, that's why you get two records printed.
You are doing complete read in the single call so your loop runs only one time hence it will output only first struct value. Change your while loop like this:
if(a)
{
a.read(reinterpret_cast<char*>(&undelivered_Factors),sizeof(undelivered_Factors));
}
for(int i=0; i<100; ++i)
{
cout<<undelivered_Factors[i].ID<<"\t"<<undelivered_Factors[i].total_price<<endl;
}

C++: FStream thinks it has reached EOF of binary file

I'm trying to read a binary file with the following format:
-64 bit integer
-3276 32-bit floats
-(Repeat last 2 lines until eof)
This is the block where I interpret the file:
ifstream bbrFile;
ofstream csvFile;
bbrFile.open(inFilename);
csvFile.open(dataFilename);
//yes I did actually check to make sure that the files had opened.
//I omitted it here for brevity
long long int time;
float point;
while (bbrFile)
{
bbrFile.read((char*)&time, sizeof(time));
csvFile << time;
for (int i = 0; i < 3276; i++) {
bbrFile.read((char*)&point, sizeof(point));
csvFile << ',' << point;
}
csvFile << "\n";
}
So far, my code is working fine, except that it thinks it's reached the end of file after reading in about 53 floats, and then just outputs the last float it read until the 'for' loop ends. I've tried using fread and FILE* instead of read and fstream, and gotten identical results. I've also tried replacing
while (bbrFile)
with
while (!bbrFile.eof())
To no avail.
Since the binary file is about 12 megabytes, I'm somewhat as a loss as to why it stops reading here.
To read the file as a binary file, you should add binary to the file mode:
bbrFile.open(inFilename, ios::binary);
otherwise it will be read as a text file, and some codes could be interpreted as an end-of-file mark.

Why is it writing strange symbols into the file in binary using the write function and not the intergers?

I have an array of 20 numbers. I'm trying to add each number into the array, but I'm doing it in binary. The reason I'm doing it in binary is because I'm trying to get ready for my exam tomorrow. This is the code I have.
file.open(fileName, ios::out | ios::binary);
for (int number = 0, index = 0; index < 20; index++) {
number = numbers[index];
if (!file.eof()) {
file.write(reinterpret_cast<char *>(&number), sizeof(number));
} else {
break;
}
}
The output of the text file is:" $1#Qdyꩃ·!Di"
Why? I know the array is populated because I've used a cout statement to see what in it. I also know that the variable used to get the number works because I've used a cout to see if it was getting the value from the array correctly.
When you write integers into a file in binary mode, you should be reading them back in binary mode as well. Text editors cannot do that.
Moreover, the data would be written in a system-specific way, i.e. either the least significant or the most significant byte first. Text editors re-interpret these numbers as characters, so you see "garbage" output.
Checking for eof() is not necessary when you write the file, so you can drop it from your code.
file.open(fileName, ios::out | ios::binary);
for (int number = 0, index = 0; index < 20; index++) {
number = numbers[index];
file.write(reinterpret_cast<char *>(&number), sizeof(number));
}
To make sure that you wrote the right data, write a small program that reads from the file in binary mode, and prints numbers as integers. You will see the numbers from the numbers[] array.

How to convert a text file into binary and vice versa?

I have made the previous problem simpler to get the answer and understand it completely.
The problem is that I want to write a C++ program that converts an ordinary text file into binary and then reads that binary file and converts it to a text file so that this text file equals to first text file.
I have wrote this simple code for it.
int main()
{
string name1 = "first", name2 = "sec", name3 = "third";
int j = 0, k = 0;
ifstream ifs(name1.c_str()); // Here I want to read from the ordinary text file (name1).
ifs >> j; // Now j equals to 5 because name1 contains digit 5.
ifs.close();
ofstream ofs(name2.c_str(), ios::binary);
ofs.write(as_bytes(j), sizeof(int)); // Here I want to write that j to name2 file in binary mode.
ofs.close();
ifstream ifs1(name2.c_str(), ios::binary); // Here I want to read from that binary file (name2).
ifs.read(as_bytes(k), sizeof(int)); // Here I hope k becomes 5.
ofstream ofs1(name3.c_str());
ofs1 << k; // Here I want to write that k to name3 file in ordinary text mode.
ifs1.close();
ofs1.close();
// Now I hope both name1 and name2 contain 5.
keep_window_open();
return 0;
}
Now what the ofs.write(as_bytes(j), sizeof(int)); or ifs.read(as_bytes(k), sizeof(int)); exactly means?
My question is why, in practice, the file name1 contains digit 5 and its size is 1 byte. The name2 contains some character/sign like [] and its size is 4 bytes and name3 contains digit 0 and its size is 1 byte?
I'll completely appreciate your responses.
Please don't extent the issue by giving extra info and only think around this problem. I want to just understand it. (My machine is Windows 7 32-bit. My compiler is MVS 2012. And if any more info is needed just tell me.)
write and read
write and read methods are used for i/o operations with binary files.
They has the following prototypes:
write(memory_block, size);
read(memory_block, size);
The write writes size bytes from memory_block to associated file.
The read reads size bytes from associated file and writes it to a memory_block
For example, in your case,
ofs.write(as_bytes(j), sizeof(int));
writes bytes of j number into a bynary file named name2.
You can see more about input and output with files here.
Why you havn't number five in name2 five
You write the bytes of j variable to name2 file in binary i/o mode. Any i/o operation is performed independently of any format considerations in this mode. It don't add carriage return after written data. This means that you can't read the name2 file and see the five number there.
Why you have a zero number in name3 file
The reason is because of typo :)
First look at the lines
ifstream ifs(name1.c_str()); // Here I want to read from the ordinary text file (name1).
ifs >> j; // Now j equals to 5 because name1 contains digit 5.
ifs.close();
And then look at the lines
ifstream ifs1(name2.c_str(), ios::binary); // Here I want to read from that binary file (name2).
ifs.read(as_bytes(k), sizeof(int)); // Here I hope k becomes 5.
You are trying to read bytes from already closed file stream object. Any operation with such objects ends up with error. You can check it out in this way:
assert(!ifs.read(as_bytes(k), sizeof(int)));
It is possible because read returns a mutable reference to ifs and ifs is convertible to boolean value.
Because of all stuff above in this section, the value of variable k stay unchanged.
You can't read from closed file, you can't change the k value. Because of this the old
value of k is written to the name3 file.
Working example
#include <assert.h>
#include <fstream>
#include <string>
using namespace std;
typedef char byte;
template<typename T>
byte* as_bytes(T* ptr) {
return reinterpret_cast<byte*>(ptr);
}
int main()
{
string
name1 = "first.txt",
name2 = "second.bin",
name3 = "third.txt";
int j = 0, k = 0;
// Here I want to read from the ordinary text file (name1).
ifstream ifs(name1.c_str());
ifs >> j;
// Now j equals to 5 because name1 contains digit 5.
assert(j == 5);
ifs.close();
ofstream ofs(name2.c_str(), ios::binary);
// Here I want to write that j to name2 file in binary mode.
ofs.write(as_bytes(&j), sizeof(int));
ofs.close();
// Here I want to read from that binary file (name2).
ifstream ifs1(name2.c_str(), ios::binary);
// Here I hope k becomes 5.
ifs1.read(as_bytes(&k), sizeof(int));
ofstream ofs1(name3.c_str());
// Here I want to write that k to name3 file in ordinary text mode.
ofs1 << k;
ifs1.close();
ofs1.close();
}

C++ line jumping and file reading

I have a file with numbers in it. I would like to read certain lines (ones that haven't been read already but are no long easily accessible due to the way my code runs)
for example..
I have code like
for (c=0; c < 5;c++)
{
in >> tmp;
}
when implemented this reads 5 parts of the first line (lines are all the same length).
I want to be able to call this same section of code again and be able to read the second..third.ect
what do I need to do to make this work
Assuming in is an input stream (istream), you can use its seekg method in order to seek back to the beginning of the file.
// read it the first time
for (c=0; c < 5;c++)
{
in >> tmp;
}
in.seekg(0, in.beg); // seek to the beginning
// read it the second time
for (c=0; c < 5;c++)
{
in >> tmp;
}
Check out the documentation of the seekg method.