C reading/writing to a file in binary mode - c

I created a File of 4000 blocks with a blocksize of 4096 Bytes.
Now I want to manipulate single blocks and read them again without changeing the files' size.
Actually I want to write blocks out of another file to specific blocks in the file I created.
Therefore I am opening the Files in binarymode like this:
FILE * storeFile=fopen(targetFile, "wb"); // this one I created before
FILE * sourceFILE=fopen(sourceFile,"rb");
now I am trying to read stuff to a pointer
char * ptr=malloc(4096);
...
for(i=0; i<blocks_needed; i++)
{
fread(ptr,4096,1,sourceFile);
// now I am going to the position of the blocks I want to write to
fseek(storeFile,freeBlocks[i]*4096,SEEK_SET);
// and now I am writing it to the File I created before
fwrite(ptr,4096,1,storeFile);
...
}
For some reason the File I created before changes it's size and becomes a copy of the file I wanted to write into it.
What am I doing wrong?
Thank you in advance!

From the fopen man page:
``w'' Truncate to zero length or create text file for writing. The stream is positioned at the beginning of the file.
You're erasing the destination file every time you open it. You might be interested in a or a+:
``a'' Open for writing. The file is created if it does not exist. The stream is positioned at the end of the file. Subsequent writes to the file will always end up at the then current end of file, irrespective of any intervening fseek(3) or similar.
``a+'' Open for reading and writing. The file is created if it does not exist. The stream is positioned at the end of the file. Subsequent writes to the file will always end up at the then current end of file, irrespective of any intervening fseek(3) or similar.

The problem is that your seek needs to be to some byte offset from the start of the file.
As the blocks are 4096 in length the offset would be (long)i * 4096;
I think you are seeking to the wrong position as the freeBlocks[i] is presumably an address.

Related

Inserting text in a file instead of overwriting in c

How can I insert characters in a file using C instead of overwriting? I also want to write in start of file and end of a file. I tried this method but it didn't work out (I can re-position but I cannot insert. The text is overwritten)
I've tried this, but it didn't work:
fword = fopen("wrote.txt", "rb+");
fseek(fword, 0, SEEK_SET);
fscanf(fword, "%c", &l);
To add text at the end, you can open the file with "a" mode (check the fopen manual). It will write your text to end.
To add text in other positions, you have to read everything after that to memory, write what you want and then write the rest.
Files are abstractions of byte streams, there is no such concept as insert in a byte stream, you can seek into certain place and write data there. The bytes you wrote will lay in the file as an array of bytes, if the writing exceeds the current file size, the file will be extended.

Prepend text to a file in C

I want to add a standard header to a file (or group of files) using C. These files could be quite large, so it would be a bad idea to load them into memory, or copy them into temporary files (I think).
Is there a way to simply prepend the header directly to each file?
The header itself is quite small, not more than 1 KB
You cannot insert data into a file.
However, there is no need to load the entire file in memory. Just create a new file, write the data you are inserting, then copy the contents of the original file to the new file (do it block by block instead of loading the entire file into memory).
Finally, delete the original file and rename the new file to match the original file.
This is the most efficient way to do this and it is reasonably efficient.
It should be possible without a temporary file - you can read the file from the end, block by block, writing each block back at (original_position + header_size). The first block would be written back at header_size, leaving room for the header.
However, you don't really want to do this. It would corrupt the file if aborted (think: out of disk space, other I/O error, power down, whatever).
Thus, you should actually use temporary file - write to it everything you need, then rename it to the original file's name (assuming you create temporary file on the same file system, otherwise you'd need to copy).
Edit: to clarify what I mean, simplified solution when the whole file fits in RAM:
allocate buffer same size as the file
open the file, and read it into the buffer
seek(file, header_size) and write the buffer here
seek(file, 0) write the header
If the file is to big, you can allocate smaller buffer and repeat reads/writes starting with read at file_size - buffer_size and write at file_size - buffer_size + header_size. Then repeat with next chunk read at file_size - 2 * buffer_size, write at file_size - 2 * buffer_size + header_size, and so on.
But let me repeat: you risk corrupting your file if it fails!

open with O_RDWR -- how to overwrite?

I want to read a file and change its content and write it back to the file.
I use open to read a file as follows:
bfd = open(m_file_name.c_str(), O_RDWR)
But when I write, it is kinda append it to the old one. How can I overwrite it?
You can use lseek(2)
bfd = open(m_file_name.c_str(), O_RDWR);
// read your file
lseek(bfd, 0, SEEK_SET);
// do whatever manipulation & write file
If your file is now less in size than the original, you will need to truncate the size to the new size, or you'll leave the bytes from the old end of the file at the end. If it's larger, the file should grow automatically as you write.
You have to seek with lseek if you want to write at a specific position.
You are not trying to overwrite the entire file, right? Just a small part of it? If you are trying to overwrite the entire file then this is a bad way to do it.

Opening a file in 'a+ 'mode

If a file is opened using the following command:
FILE *f1=fopen("test.dat","a+");
The man page reads:
a+
Open for reading and appending (writing at end of file). The
file is created if it does not exist. The initial file position
for reading is at the beginning of the file, but output is
always appended to the end of the file.
So does f1 have 2 separate offset pointers, one for read & another for write?
No.
There is just one pointer which initially is at the start of the file but when a write operation is attempted it is moved to the end of the file. You can reposition it using fseek or rewind anywhere in the file for reading, but writing operations will move it back to the end of file.
No it has only one pointer.
You can never mix reading and writing operations on a FILE without calling fseek in between. It may work as you wish on some implementations, but a program that depends on this has undefined behavior. Thus the questions of having 2 positions is meaningless.

How do I overwrite X bytes on offset Y with fwrite()?

All I can find using fopen() and fwrite() in C is to delete all contents and start writing again or append to the end of the file. What if I need to go to some offset in the file and overwrite a few bytes?
Is that possible with some function?
You can open the file with the "rb+" option and then use fseek with SEEK_SET to go to a specific location. Therb+ opens it for both reading and writing as a binary file (the file must exist in order for it to succeed - it will not create a new file).

Resources