open with O_RDWR -- how to overwrite? - c

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.

Related

Reading a string from a file with C. Fopen with w+ mode is not working

I made a C program that reads a string from a .txt file, then it encrypts the string, and finally it writes the string in the same file.
The thing is that if I use fopen("D:\\Prueba.txt","w+"), the program doesn't work, it prints garbage like this )PHI N.
I've debugged and I know the error is there in that line, because if I use fopen("D:\\Prueba.txt","r+"), the program works, and it writes what it should.
But I want to use w+ because it will rewrite what the .txt file had. Why is w+ not working?
If you're opening with w+ to first read the content, that's not going to work. From C11:
w+: truncate to zero length or create text file for update.
What's probably happening is that you read data from the now empty file but don't correctly check that it worked. That would explain the weird "content" you see of )PHI N.
One solution is to open the file as with r, open another file with w, and transfer the contents, encrypting them as part of that process. Then close both, delete the original, and rename the new one to the original name. This will allow you to process arbitrarily-sized files since you process them a bit at a time.
If you don't want to use a temporary file, and you're sure you can store the entire content in memory, you could open it r+, get the content, the reopen it with a new mode, such as with:
FILE *readFh = fopen( "myfile.txt", "r+");
// Read in content, massage as needed.
FILE *writeFh = frepoen( NULL, "w+", readFh);
// Provided that worked, you should now have an empty file to write to.
// Write back your massaged data.

C reading/writing to a file in binary mode

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.

Reading from a file opened using append mode

It might be a very dumb question but I am modifying someone else's code and it seems I need to read from a file that was opened in append mode. I tried to fseek to the beginning of the file but nothing is being read.
I know I can change the mode to rw but I wanted to know why fseek is not working. In the man page it does say write ignores fseek but nothing about read though.
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.
When you open in append mode, the file pointer is returned to the end of file before every write. You can reposition the pointer with fseek for reading, but as soon as you call a function that writes to the file, the pointer goes back to the end of file.
The answer at Does fseek() move the file pointer to the beginning of the file if it was opened in "a+b" mode? references the appropriate section of the C standard.
Use the "w+" mode if you would like to write to arbitrary places in file. An existing file will be overwritten.
If you would like to append to an existing file initially, but then fseek to arbitrary place, use "r+" followed by
fseek(f, 0, SEEK_END)
Hope it helps..

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!

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