How can C read content that is newly inserted into a file? - c

I want to first write something to a file, then use fgets to read it. But I want it to work without close it and switch file open mode between read and write,
I have tried r+ and w+ for file open. For r+ it is able to read original content but fail to read newly inserted content. For w+ it does not read anything I think that's because w+ clear the original content.
I currently found no way to read the newly inserted content of a file before close and switch file open mode, although with fflush new content is already written to a file and can be viewed externally.
Here is a simple code snippet for testing.
#include <stdio.h>
int main()
{
FILE *fp = NULL;
char line[256];
int status;
/*input by user*/
scanf("%s", line);
/*write to a file*/
fp = fopen("f5.txt", "w+");
fprintf(fp, "%s", line);
fflush(fp); /*flush buffer*/
/*read it*/
char lineRead[256];
while (fgets(lineRead, 5, fp) != NULL) {
puts(lineRead);
}
fclose(fp);
}

You might use not only fflush, but also rewind, fseek, ftell (or even fgetpos & fsetpos)
Beware that any standard IO function can fail, and you should check that.
On Linux, some files (e.g. fifo(7)) are not seekable.
Perhaps you want some higher level way of storing persistent data on the disk. Did you consider using some library for indexed files (like gdbm) or for databases (like sqlite)? Or even use a full fledged database, like with some RDBMS (e.g. PostGreSQL or MySQL or MariaDB which are free software), or some NoSQL thing like e.g. MongoDB ?
There is no way to insert a sequence of bytes in the middle of some file or to delete, i.e. remove, a sequence of bytes inside a file. This is a fundamental limitation of file systems on most current operating systems (and on all usual ones like Linux & Windows & Android & MacOSX). You generally should copy that file (by chunks) into some other one (and libraries like gdbm or sqlite don't do that, they either append some data to a file at its end or rewrite some bytes inside the file; they might also truncate a file).
In particular, if you want to programmatically insert some line in the middle of some small text file, you usually should read the file entirely in some appropriate data structure, modify that data structure in memory, then dump that data structure into the (overwritten) file.

You need to use fseek() to return to the beginning of the file before trying to read it.

Related

Reading content from a file and storing it to String in C

I've written a simple http server in C and am now trying to implement HTML files.
For this I need send a response, containing the content of the HTML file.
How do I do that best?
Do I read the file line by line, and if so how do I store them in a single string?
Thanks already!
Here is an example of reading a text file by chunks which, if the file is big, would be faster than reading the file line by line.
As #tadman said in his comment, text files aren't generally big so reading them in chunks doesn't make any real difference in speed but web servers serve other files too - like perhaps photos or movies (which are big). So if you are only going to read text files then reading line by line might be simpler (you could use fgets instead of fread) but if you are going to read other kinds of files then reading all of them in chunks means you can do it the same way for all of them.
However, as #chux said in his comment, there is another difference between reading text files and binary files. The difference is that text files are opened in text mode: fopen(filename,"r"); and binary files must be opened in binary mode: fopen(filename,"rb"); A web server could probably open all files in binary mode because web browsers ignore whitespace anyway but other kinds of programs need to know what the line endings will be so it can make a difference.
https://onlinegdb.com/HkM---r2X
#include <stdio.h>
int main()
{
// we will make the buffer 200 bytes in size
// this is big enough for the whole file
// in reality you would probably stat the file
// to find it's size and then malloc the memory
// or you could read the file twice:
// - first time counting the bytes
// - second time reading the bytes
char buffer[200]="", *current=buffer;
// we will read 20 bytes at a time to show that the loop works
// in reality you would pick something approaching the page size
// perhaps 4096? Benchmarking might help choose a good size
int bytes, chunk=20, size=sizeof(buffer)/sizeof(char);
// open the text file in text mode
// if it was a binary file you would need "rb" instead of "r"
FILE *file=fopen("test.html","r");
if(file)
{
// loop through reading the bytes
do {
bytes=fread(current,sizeof(char),chunk,file);
current+=bytes;
} while (bytes==chunk);
// close the file
fclose(file);
// terminate the buffer so that string function will work
*current='\0';
// print the buffer
printf("%s",buffer);
}
return 0;
}

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.

live update on file /proc/<pid>/status when open

I am trying to read information from the /proc/<pid>/status file (to get the memory used).
To do this, I open the file in read mode:
file = fopen("/proc/self/status", "r");
After this step, to get the memory, I read the line that starts with "VmRSS".
My problem is this:
Each time I read this line, it's the same value, even if the file has changed.
I am doing this to get real-time memory usage of my program. So I call fopen() 1 time,
and then I call fseek() to go to the beginning of my file when I need updated information.
char line[128];
fseek(file, 0, SEEK_SET);
while (fgets(line, 128, file) != NULL)
{
//...
}
But, the file is not updated, unless I reopen it. I don't want to reopen it for performance reasons.
I tried to change "r" to "r+" (to have a "Open a file for update", according to the documentation of fopen()), but fopen returns NULL in this case.
So my question:
Do you have any idea on how my program can open a file and see changes from made by another programme (here the kernel) using only one call to fopen()?
Note :
I use Ubuntu 12.04
You need to reopen the file To avoid race conditions,
proc is a file system in memeory and most /proc content are being fixed on open.
Maybe you can open the /proc/<pid>/status file with open but not fopen.
int fd = open('/proc/<pid>/status', O_RDONLY, MYF(0));
// read
seek(fd, 0L, MY_SEEK_SET, MYF(0));
// read

Inserting data to file in c

I need to add a string before the 45th byte in an existing file. I tried using fseek as shown below.
int main()
{
FILE *fp;
char str[] = "test";
fp = fopen(FILEPATH,"a");
fseek(fp,-45, SEEK_END);
fprintf(fp,"%s",str);
fclose(fp);
return(0);
}
I expected that this code will add "test" before the 45th char from EOF, instead, it just appends "test" to the EOF.
Please help me to find the solution.
This is continuation of my previous question
Append item to a file before last line in c
Open it with mode r+ (if it already exists) or a+ (if it doesn't exist and you want to create it). Since you're seeking to 45 bytes before the end of file, I'm assuming it already exists.
fp = fopen(FILEPATH,"r+");
The rest of your code is fine. Also note that this will not insert the text, but will overwrite whatever is currently at that position in the file.
ie, if your file looks like this:
xxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
Then after running this code, it will look like this:
xxxxxxxtestxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx
If you really want to insert and not overwrite, then you need to read all the text from SEEK_END-45 to EOF into memory, write test and then write the text back
Don't open it as append (a) if you plan to write at arbitrary positions; it will force all writes to the end of the file. You can use r+ to read or write anywhere.
To avoid platform-specific configurations, always explicitely indicate the binary or text mode in your fopen() call.
This will save you hours of desperations if you port your code one day.

Seeking to beginning of file

I have a small code block that should append text to the beg of a file. However it still only adds to the end of the file. I thought the rewind set the pointer to the front of the file, thus when I added the text using fprintf it should add to the front. How can I change this?
fp = fopen("Data.txt", "a");
rewind(fp);
fprintf(fp, "%s\n", text);
fclose(fp);
Text is a char array to be added at the front of the file
1) Don't open in append mode.
When you open in append mode, all writes go to the end of the file, regardless of the seek position.
http://www.opengroup.org/onlinepubs/009695399/functions/fopen.html
Opening a file with append mode (a as
the first character in the mode
argument) shall cause all subsequent
writes to the file to be forced to the
then current end-of-file, regardless
of intervening calls to fseek().
2) Opening without "a" still won't do what you want. It's not possible to insert into a file using the ANSI/POSIX file operations, because given the way most file systems store their data, insert is not a simple operation.
You need either to open a new file, write your new data, then append the old file afterwards, or else you need to mess around shuffling data forward in blocks. Either option is very inefficient for large files, compared with appending at the end, not to mention error-prone if you need the program or the machine to be able to unexpectedly die without corrupting data. So if this is a log file or similar, it's probably worth redesigning so that you can write new data to the end, and then reverse it all when you prepare a report from the log.
You can replace data in a file, but you can't prepend or insert it anywhere but at the very end of the file.
Just create a new file with your data and then append the old data in this file you created.

Resources