Writing data to a binary file, then reading it back - c

I am trying to write data to a binary file and then read back the data from the file. The data consists of a single number (an integer) nrows. Below is my code for writing the data to a binary file. However, when I try to read back the data and print the result using printf, I obtain a nonsensical result: -2.
FILE *fout;
FILE *file_pointer;
int nrows = 5;
fout = fopen("matrixB.bin", "wb") //Writing to a binary file.//
fwrite(&nrows, sizeof(int), 1, fout); //Writing the number nrows to the binary file "matrixB.bin"//
file_pointer = fopen("matrixB.bin", "rb"); //Reading a binary file.//
fread(&nrows, sizeof(int), 1, file_pointer);
printf("%d", nrows); //Here -2 is printed, instead of 5.//
What is the problem with my code?

One of the characteristics of the C file functions (fread, fwrite, etc) is that they normally perform buffered I/O.
Your program doesn't flush and/or close the file before reopening it. It should.

Related

Reading a text file full with null characters and texts using fread

I am trying to design a small file system.
I have created a text file to store the files data in.
int kufs_create_disk(char* disk_name, int disk_size){
FILE* file_ptr = fopen(disk_name, "w");
if (file_ptr == NULL)
return -1;
fseek (file_ptr, disk_size * 1024-1, SEEK_SET);
fwrite("", 1, sizeof(char), file_ptr); // to make a size for the file
fclose(file_ptr);
DiskName=disk_name;
return 0;
}
After writing to the file I get a file with the size I determine when I call the function.
kufs_create_disk("test.txt", 5);
which creates a file with size of 5kbs with '\0' to fill this file to the size.
I have created another function to write to this file in different places of the file which works just fine and I won't paste the code for simplicity.
When I try to read from the file using fread(), I'm not getting all the data I have written into the memory; rather I get just some of the data.
My read implementation would be:
int kufs_read(int fd, void* buf, int n){
FILE *file_ptr= fopen("test.txt","a+");
fseek (file_ptr, FAT[fd].position, SEEK_SET); //where FAT[fd].position is where I want to start my read and fd is for indexing purposes
fread(buf, 1, n, file_ptr); //n is the number of bytes to be read
FAT[fd].position = FAT[fd].position + n;
}
The thing is the file reads some of the characters written and doesn't read the rest. I did a little test by looping all over the file and checking whether every thing is being read and fread reads every thing but in the buf I only get some of the characters I've written.
The text file looks something like this:
0\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00written string1written string2 0\00\00\00\00\00\00\00\00\00\00\00\000\00\00\00\00\00\00\00\00\00\00\00\00writtenstring 3 \00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00
I get writtenstring1 and writtenstring2 in the buffer but I don't get writtenstring 3 for example.
Can you explain why?

Reading and writing integers to a binary file using C?

I am trying to write 100 integers to binary file. I have tried writing to this file, and reading from it. When reading from it I get completely random digits.
Here is the block concerning the write.
Do note I have the file open for write with "wb" mode. I have also closed the file at the end.
for (int i = 0; i < 99; i++) {
fwrite(&i, sizeof(int), 1, file);
}
Here is the block concerning the read.
Do note I do have the file open here in "rb" mode and it is closed.
int num;
for (int i = 0; i < 100; i++) {
int rc = getc(file);
if (rc == EOF) {
fputs("Error occured while reading file", stderr);
return EXIT_FAILURE;
}
fread(&num, sizeof(int), 1, file);
printf("%d", num);
}
My output is like this:
-13421772802147469895-168955699232767012640583688388440-104919389914260634872147467638000128293273683884400-19797114882147440795-168947558432767-1097029212883066888388440148657280313254001912147440795-168942592032767-109702911303445504838844014865730434362077432147440795-168935577632767-1097029063753420883766251486573257-6039796492147440795-168932864032767-109702901326841856838844014865733541270-168949760032767-10970289133241241683884401486573450-1090518913214744079500196944831217016018891752457584192041348617175279241952408940298110176910929517683167731702125413116313304413809989891296126535181930809719192433591818324585127960891517680423011935761967-13421772802147469895-168955699232767012640583688388440-104919389914260634872147467638000128293273683884400-19797114882147440795-168947558432767
So there is something wrong, and I am not sure what exactly. Perhaps I am not sure if I understand the API for reading/writing completely (specifically size_t nitems)? I am not sure how to tell how many bytes I need to read/write from a file.
In the first loop, you are writing 100 integers starting at the address of 'i', 99 times.
Not what I think you were thinking you were doing.
it should be
fwrite(&i, sizeof(int), 1, file);
Secondly, what mode do you open the file for writing? It should be opened in binary mode otherwise it will not save binary data correctly (add 'b' to the fopen mode value)
DO you close and reopen the file for the read (and set the right file mode?) or if I was left open, do you fseek back to beginning of the file before trying to read the values.

Why does the calling of dup2 go wrong?

As you see, the program has two file pointer sport and fruit point to the file fruit.txt. The problem is that after run the program, sport.txt is empty and fruit.txt contains Chinese characters. I expected that the sport.txt should contains the word "basketball" because it is written to the file before redirecting happens. So, what is wrong here?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "../cus_header/cus_header.h"
int main(){
FILE *fruit = fopen("fruit.txt", "w");
if(!fruit)
error("cannot open fruit.txt");
FILE *sport = fopen("sport.txt", "w");
if(!sport)
error("cannot open sport.txt");
int de_sport = fileno(sport);
int de_fruit = fileno(fruit);
printf("file number of sport.txt: %i and of fruit.txt: %i\n", de_sport, de_fruit);
fwrite("basketball", sizeof(char), 10, sport);
fwrite("apple", sizeof(char), 6, fruit);
if(dup2(de_fruit, de_sport) == -1)
error("cannot redirect");
fwrite("basketball", sizeof(char), 10, sport); //???
fwrite("apple", sizeof(char), 6, fruit); // ???
fclose(sport);
fclose(fruit);
return 0;
}
As the comments already mention, you shouldn't mix file manipulation with streams (using FILE*, fopen, fwrite, fclose) with raw file manipulation (using file descriptors, open, write, close, dup2). And especially don't mix them on the same file pointer/descriptor like you are doing in this piece of code.
Let's go through the code to see why it behaves the way it does:
FILE *fruit = fopen("fruit.txt", "w");
...
FILE *sport = fopen("sport.txt", "w");
You shouldn't care about how the FILE structure looks like, let's just suppose it keeps the underlying file descriptor somewhere.
int de_sport = fileno(sport);
int de_fruit = fileno(fruit);
You create local variables holding the same file descriptors as the two FILE* refer.
fwrite("basketball", sizeof(char), 10, sport);
fwrite("apple", sizeof(char), 6, fruit);
You write something in each of the two files. Because C file streams are buffered by default, the actual writing in the file on disk might not happen right away (and in your case it doesn't).
dup2(de_fruit, de_sport)
This closes the file descriptor de_sport and makes it refer to the same file as de_fruit. The actual numerical values remain the same, only the actual files that they refer to are changed. This means that the two FILE handles will write to the same file after the dup2 call.
fwrite("basketball", sizeof(char), 10, sport); //???
fwrite("apple", sizeof(char), 6, fruit); // ???
This will write to the same underlying file because the two descriptors now refer to the same file. But again, because streams are buffered, this might actually just append to the buffers of those two FILE*s.
fclose(sport);
fclose(fruit);
This flushes the buffers, so the actual writing to disk happens here. Because the descriptors have been changed, if no flushing happened until now, both streams will actually flush to the same file on disk.
This is probably why you're seeing that behavior, but keep in mind that what you're doing is not safe and that the behavior or file contents might differ.

Writing to File with Offset

I'm trying to write a simple block of code that writes the contents of an array to a position in a file. The file is a simple, text only file. It seems to do everything write, but file contents end up in hex (with a bunch of zeroes at the beginning). I'm using the following:
FILE * fp; // file to write to
void fwritel(long offset, char * data) {
fp = fopen(filename, "w");
fseek(fp, offset, SEEK_SET);
fwrite(data, 1, strlen(data) - 1, fp);
fclose(fp);
}
I've also used a variation of pwrite that didn't work: pwrite(fp, data, strlen(data) - 1, offset); The code I'm looking for would write data at position offset only modifying the file from offset to offset + strlen(data).
This is a multiple part fix:
Joachim Pilebord is right. Opening the file using fopen(file, "w") will destroy the contents of the file. So each time it would open the file, zero the file, then write the new contents.
M Oehm was also correct, the new content would be padded with zeros - thus Sublime treated it as hex.
So, opening the file once, somewhere at the beginning of the program, using only
fseek(fp, offset, SEEK_SET);
fwrite(data, 1, strlen(data), fp);
and closing the file somewhere near the end of the program produces the correct output. Using fputc(' ') would work but you'd need to make sure I'm not replacing characters that you need (i.e. previously placed data in those parts of the file).

How can I read from and write to a binary file simultaneously?

I want to change the value of a couple of bytes in a large binary file using MATLAB's fwrite command. What I am trying to do is open the file using:
fopen(filename,'r+',precision);
Then read down the file using:
fread(fid,NUM,'int32');
This all works. Once I get to the file position where I want to write (overwrite) the values of the next bytes, I use the command:
fwrite(fid,variable_name,'int32');
Then I close the file:
fclose(fid);
So then I go back and re-read the file and these bytes haven't changed!
So is this not possible? Or is 'r+' the wrong thing to use?
From the documentation for fopen:
To read and write to the same file:
Open the file with a value for permission that includes a plus sign, '+'.
Call fseek or frewind between read and write operations. For example, do not call fread followed by fwrite, or fwrite followed by fread, unless you call fseek or frewind between them.
In short, you need to call fseek before you call fwrite:
fid = fopen(filename, 'r+', precision);
data = fread(fid, NUM, 'int32');
fseek(fid, 0, 'cof');
fwrite(fid, variable_name, 'int32');
fclose(fid);
In fact, if you don't actually need to read anything from the file, and just need to move to a given position in the file, I would just use fseek in place of your call to fread. For example:
fid = fopen(filename, 'r+', precision);
fseek(fid, NUM*4, 'bof');
fwrite(fid, variable_name, 'int32');
fclose(fid);
When you read to know which byte to change keep a count of how many bytes you have to skip (4 bytes each int or float for instance).
bytesToSkip = 0;
not_the_value_you_want = true;
bytesPerValue = 4; %for a float or int
while not_the_value_you_want
...some code here...
if 'this is it'
not_the_value_you_want = false; % adapt this to your taste
else
bytesToSkip += bytesPerValue;
end;
...maybe more code here...
end;
Try this after:
fileID = fopen('YourFile.bin','w+');
fseek(fileID,bytesToSkip,'bof'); %'bof' stands for beginning of file
fwrite(fileID,newValue);
fclose(fileID);

Resources