I want to store data from desired byte upto another desired byte of the file opened in binary mode in to another file. Lets say file pointer is at byte# 10, now i want to read data from byte # 11 to byte # 30. I know i have to use fread() function but don't know how to tell this function to read from desired location upto another desired location. I am a beginner so bear answering this question.
I know fread() is C function, I want C++ equivalent functions for doing this work. A link or suggestion of book for learning file handling will be great!
Thanks alot for your help!
You have to seek:
std::ifstream infile("source.bin", std::ios::binary);
infile.seekg(10, std::ios::beg); // seek to 10 bytes from the beginning
char buf[20];
if (!infile.read(buf, 20)) { /* error */ }
// now your data is in buf
The stdio interface is is similar, but since this is C++, we prefer the iostreams one. You must never, ever use I/O operations without checking their return value, and in iostreams this is fairly easy. With fread you have to be careful to interpret the return value correctly.
Well, the prototype for fread is :
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
And fseek is:
int fseek ( FILE * stream, long int offset, int origin );
If you want to get to byte #11, you can do:
fseek(file, 11, SEEK_SET) // this means: go 11 bytes from the start position.
or, since you're already at byte 10, you can do:
fseek(file, 1, SEEK_CUR) // this means: go 1 byte beyond current position.
Then, to read up to byte 30 from byte 11, you need to read 19 bytes (30 - 11), so you do:
fread(buffer, sizeof(char), 19, file).
Related
Here is my C++ homework. Given a binary file, this file consists of some data units. Every data unit contains two parts. The first part is 1 char and the second part is 1 int. Read the whole file into a buffer at a time and then extract all data units from the buffer.
Now I've read the file into a buffer successfully like this:
char* readBinaryFile(const char* fileName) {
ifstream file(fileName, ios::binary || ios::ate);
// get the size of file
streampos beg, end;
beg = file.tellg();
file.seekg(0,ios::end);
end = file.tellg();
long size = end - beg;
char* buffer = new char[size];
// now read the file into buffer
file.seekg(0, ios::beg);
file.read(buffer, size);
file.close();
return buffer;
}
So my problem is how can I get the data unit from the buffer?
I'm not going to write the code for you, but think about this for a moment...
At buffer[0] is your first char. At buffer[1] through buffer[4] is your first int. It repeats, so buffer[5] is the character for the second set of data.
There are five bytes for the character and the int together. If you know the amount of data you've read, you could divide that by 5 and know the number of "sets" of data there is.
You can now use something like a for loop to iterate from zero to the numbers of sets minus one. Let's say this iterator variable is i, then you could access the character of each "set" of data with buffer[i * 5], the first byte of the int at buffer[i * 5 + 1], etc.
So, a for loop and a little bit of math will help you extract the information from that buffer. You'll have 5 individual bytes, and you'll need to reassemble 4 of those bytes back into an int. There are a variety of ways of accomplishing this, which I'll let you attempt to discover.
Could your issue stem from the fact that you're using:
ios::binary || ios::ate
when I think you mean:
ios::binary | ios::ate
The former evaluates to "1", since binary logical-or at-end is "true", the latter is a bitmask that says "open this file in binary mode, and at the end". The way you have written it is actually the equivalent of
ios::app
I would like to read the data with fread from file. However, I encounter the problem of setting of NULL terminator.I think the the line (fileMem[fileSize] = 0;) should have been solved. However, I still get rubbish at the with I check the value of "fileMem". Would anyone help me to find the problem?
I followed other posts about setting the NULL terminator but just does not work
File *input = fopen(filePath, "r");
fseek(input, 0, SEEK_END);
auto fileSize = ftell(input);
fseek(input, 0, SEEK_SET);
char* fileMem = new char[fileSize+1];
fileMem[fileSize] = 0;// the NULL terminator problem should have been solved here
clearerr(input);
fread(fileMem, fileSize,1, input);
What is the problem with my code?
fread is reading more bytes than fileSize, because you are specifying a record size of fileSize, and asking it to read only one text record. It then overwrites the 0 at the end with actual data, so you get garbage.
fread returns the number of bytes it actually read, so you can allocate a bigger buffer, then use the return value from fread to determine how much of it is valid (and to set a null-terminator).
Since it is updating your data in this way, I also suggest changing the file type to binary ("rb" rather than "r" in call to fopen).
The reason this is happening is because fread performs translation of text when in text mode ("r" rather than "rb"), such as carriage returns and line feeds.
Assuming you are on Windows, I think the problem is that you are opening the file in text mode and using fread which is meant for binary mode. In text mode, what you read may not be exactly what is in the file. Windows text files have "\r\n" at the end of the file, but in text mode this two character combination is converted to a single character, "\n". So the fileSize you computed will be too large and so your null terminator will be in the wrong place.
To verify this, change your fread to be:
int nr = fread( fileMen, 1, fileSize, input);
Swapping the middle args, will have fread return the number of bytes read. If you look at the value of nr, it will be smaller than fileSize because of the line end translation.
This wouldn't be a problem on a *nix system since there is no translation there in text mode.
When you want to use fread to read the contents of a file, you must open the file in binary mode.
FILE *input = fopen(filePath, "rb");
^^
Otherwise, the size of the file you get by using
fseek(input, 0, SEEK_END);
auto fileSize = ftell(input);
will be greater than the number of characters that what can be read by fread.
If you have a CR and a LF, they will count as two characters by the above method but fread will read only one character. Hence, fread will read less than fileSize characters. You can also change the fread line to:
// Swap the middle arguments.
// The first argument is supposed to be the size of each object.
// The second argument is supposed to be the number of objects to read.
auto n = fread(fileMem, 1, fileSize, input);
if ( n != fileSize )
{
// Surprise
}
fileMem[n] = '\0';
I want to write three characters to a file, then a struct, then one more character.
Finally I would like to read the character before the struct, the struct itself, the character after the struct and display them on the screen.
struct stuff{
int a;
int b;
};
int main(){
FILE * fp = fopen("input.txt", "w+");
char charA = 'z';
char charB = 's';
char charC = 'q';
char charD = 'e';
//create a struct of type stuff
stuff s;
s.a = 123;
s.b = 2111;
//fwrite three first chars
fwrite(&charA, 1, sizeof(char), fp);
fwrite(&charB, 1, sizeof(char), fp);
fwrite(&charC, 1, sizeof(char), fp);
//fwrite the struct
fwrite(&s, 1, sizeof(struct stuff), fp);
//fwrite the last char
fwrite(&charD, 1, sizeof(char), fp);
//read the char before the struct, the struct itself,
// and the char after the struct
char expectedCharC;
stuff expectedStructS;
char expectedCharD;
fseek(fp, sizeof(struct stuff) + sizeof(char), SEEK_END);
fread(&expectedCharC, 1, sizeof(char), fp);
fread(&expectedStructS, 1, sizeof(struct stuff), fp);
fseek(fp, sizeof(char)*3 + sizeof(struct stuff), SEEK_SET);
fread(&expectedCharD, 1, sizeof(char), fp);
cout<<expectedCharC<<" "<<expectedStructS.a<<" ";
cout<<expectedStructS.b<<" "<<expectedCharD<<endl;
fclose(fp);
return 0;
}
Instead of this result:
q 123 2111 e
I get this result:
4197174 0 e
I don't know what I'm doing wrong. I'm writing bytes to the file, reading them back and displaying them on the screen. What goes wrong?
thank you in advance
Wow, lots of problems in your code. Let's tackle them one by one.
As mentioned by unwind, the mode you're using to open the file seems to be incorrect as to what you're trying to do. For one, you're trying to read from a file that is opened for write-only.
You're using fwrite wrongly. It goes fwrite(pointer to data, size of each data, number of data, FILE pointer);.
You're using fseek wrongly. I see you're confused with the offset parameter. This offset defines a signed distance from the origin specified as the last argument to fseek. Therefore, if you're at SEEK_END, you should be moving backwards by having your offset be a negative number.
I've done these changes myself and now it works. Output: q 123 2111 e
Here's a nice little website for you too. Helped me with your problem.
Thank you for reading.
First, as has been pointed out, you must open the file in binary
mode. Even then, just dumping the bytes of a struct means
that you won't be able to read it correctly some time in the
future. But as long as you're reading from the same process, it
should be OK.
The real problem is what you are doing with all of the fseek:
before the first fread, you do an fseek beyond the end of
the file. Any read from that position is guaranteed to fail.
You really should check the status of the file, and ensure that
the fread has succeeded before accessing any of the values you
read. If it failed, accessing the variables (at least those in
stuff) is undefined behavior; most likely, you'll get some
random garbage.
Your first fseek should probably be to the beginning of the file, or
else:
fseek( fp, -(sizeof( stuff ) + 4), SEEK_BEG);
If you've just read the struct, then the second fseek is
unnecessary as well. (In your case, it means that the final
'e' is correctly read.)
You must open your file in binary mode for this to work.
FILE * fp = fopen("input.txt", "wb+");
^
|
blam!
Your wanted result is also a bit unclear, shouldn't it start with the three characters 'z', 's' and 'q', and then have the integers? Note that the integers are likely to appear byte-swapped if you're on a little-endian machine.
To help debug the code, you should add return-value checking to all I/O calls, since I/O can fail. Also note that sizeof (char) is always 1, so it's not very beneficial to write it like that.
I am serializing some data to a file like this:
vector<ByteFeature>::iterator it = nByteFeatures.Content().begin();
for (;it != nByteFeatures.Content().end(); ++it)
{
for ( int i = 0; i < 52; i++)
{
fwrite( &it->Features[i], sizeof(unsigned char), 1, outfile);
}
}
But I would like to know in advance how much bytes that will be in the file.
I would like to write this number in front of the actual data.
Because in some situations I will have to skip loading this data, and I need to know how many bytes I have to skip.
There is more data written to the disk, and it would be crucial to me that I can write the number of bytes directly before the actual data. I do not want to store this number in a separate file or so.
.Content.size() would only tell me how many "items" are in there, but not the actual size of the data.
Thank you.
I've had to do this before myself.
The approach I took was to write a 4-byte placeholder, then the data, then fseek() back to the placeholder to write the length.
Write a 4-byte placeholder to the file.
ftell() to get the current file position.
Write the data to the file.
ftell() to get the new position.
Compute the length: the difference between the two ftell() values.
Then fseek() back to the placeholder and write the length.
You are writing 52 unsigned chars to a file for every ByteFeature. So the total number of bytes you are writing is 52 * nByteFeatures.Contents().size(), assuming that one char equals one byte.
I have an array of size 668x493 which i want to save. So i am doing the following.
data : is a pointer to an array that holds the values.
long lSize;
FILE* image_save;
image_save=fopen("image_save_file.bin","w+b");
fwrite(data,1,329324,image_save);
However, when i read back this array:
char* check_image;
p1File=fopen("image_save_file.bin","r+b");
fseek (p1File , 0 , SEEK_END);
lSize = ftell (p1File);
fseek (p1File , 0 , SEEK_SET);
when i check lSize, i see it 327680 ???
So of course when i do fread i get only 327680 values !
Kindly asking, can you pinpoint my mistake ?
Interestingly, 327680 is an exact multiple of 4096 (80 * 4096).
Are you flushing/closing the output file before you read the data back in?
The fwrite() function is buffered. Try flushing the data on the file stream and try again.
fwrite returns an int indicating the actual number of bytes written. Double check to make sure this differs from expected (it almost certainly does). Then, you can use perror to print out the error that's occurring.