clear/truncate file in C when already open in "r+" mode - c

My code currently looks something like this (these steps splitted into multiple functions):
/* open file */
FILE *file = fopen(filename, "r+");
if(!file) {
/* read the file */
/* modify the data */
/* truncate file (how does this work?)*/
/* write new data into file */
/* close file */
fclose(file);
}
I know I could open the file with in "w" mode, but I don't want to do this in this case. I know there is a function ftruncate in unistd.h/sys/types.h, but I don't want to use these functions my code should be highly portable (on windows too).
Is there a possibility to clear a file without closing/reopen it?

With standard C, the only way is to reopen the file in "w+" mode every time you need to truncate. You can use freopen() for this. "w+" will continue to allow reading from it, so there's no need to close and reopen yet again in "r+" mode. The semantics of "w+" are:
Open for reading and writing. The file is created if it does not exist, otherwise it is truncated. The stream is positioned at the beginning of the file.
(Taken from the fopen(3) man page.)
You can pass a NULL pointer as the filename parameter when using freopen():
my_file = freopen(NULL, "w+", my_file);
If you don't need to read from the file anymore at all, when "w" mode will also do just fine.

You can write a function something like this:(pseudo code)
if(this is linux box)
use truncate()
else if (this is windows box)
use _chsize_s()
This is the most straightforward solution for your requirement.
Refer: man truncate and _chsize_s at msdn.microsoft.com
and include necessary header files too.

Related

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

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.

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

Read and write in place not writing?

New to C and I'm trying to do a text replace in place. I thought r+ in fopen should allow me to read and write. I'm looking at every line in the file and if it begins with a / then I am prepending http://example.com to the beginning of the line. Example...line is /tree then that line becomes http://example.com/tree. The regex works fine. I can read the file fine but it is not writing. Any ideas why?
void
fix_relative (char *page)
{
FILE *fp;
fp = fopen ("file", "r+");
char line[1000];
regex_t re;
regcomp (&re, "^/", REG_EXTENDED);
while (fgets (line, sizeof line, fp) != NULL)
{
if (regexec (&re, line, 0, NULL, 0) == 0) {
fprintf (fp, "http://example.com%s\n", line);
}
}
fclose (fp);
}
No way this can possibly work. You will run into a problem as soon as your new string is not exactly as long as the original string. In addition, since you are working in text mode, there may be additional artefacts because of newline/carriage return translation.
Instead, do the following:
open the file "file" for reading only
create a new temporary file for writing only
read a line, modify if necessary, write to new file
when done, delete "file" and rename your temp file.
This may help you to understand your problem
fopen function
Purpose:
Opens a stream. The safer fopen_s function is also available.
Syntax:
FILE * fopen(const char *name, const char *mode);
Declared in:
The fopen function opens the file whose name is the string pointed to by name, and associates a stream with it. The string may contain a full path (from the root), a relative path (from the current directory) or just a name.
The argument mode points to a string. If the string is one of the following, the file is open in the indicated mode.
"r" Open text file for reading.
"w" Truncate to zero length or create text file for writing.
"a" Append; open or create text file for writing at end-of-file.
"rb" Open binary file for reading.
"wb" Truncate to zero length or create binary file for writing.
"ab" Append; open or create binary file for writing at end-of-file.
"r+" Open text file for update (reading and writing).
"w+" Truncate to zero length or create text file for update.
"a+" Append; open or create text file for update, writing at end-of-file.
"rb+" Open binary file for update (reading and writing).
"wb+" Truncate to zero length or create binary file for update.
"ab+" Append; open or create binary file for update, writing at end-of-file.
"r+b" Same as "rb+"
"w+b" Same as "wb+"
"a+b" Same as "ab+"
Opening a file with read mode ('r' as the first character in the mode argument) fails if the file does not exist or cannot be read.
Opening a file with append mode ('a' as the first character in the mode argument) causes all subsequent writes to the file to be forced to the then current end-of-file, regardless of intervening calls to the fseek function.
When a file is opened with update mode ('+' as the second or third character in the mode argument), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end-of-file.
When opened, a stream is fully buffered if and only of it can be determined not to refer to an interactive device. The error and end-of-file indicators for the stream are cleared.
Returns:
A pointer to the object controlling the stream on success, otherwise a null pointer.
One thing that may not be clear: if you update lines in the file, and your replacement text is not precisely the same length as what it is replacing, you will make a complete hash of the file: you will be overwriting what comes after it.
So, if you have a file that contains the sentences:
I love programming.
I love life.
and you set the file position to the first sentence and replace "love" with "loathe", you will NOT get
I loathe programming
I love life
You will get
I loathe programming love life
because you have now overwritten the line separator from the first sentence, and the "I" from the next sentence.
If you replace a string with a longer string, that will push every other character in the file forward. To do that replacement, you'd have to read the entire file into memory, do your replacements, and then write the file back out to disk.

Completely close a file in c

I need to read, and then write to a file. I don't want to use "r+" because I completely overwrite it anyway. But I am unable to completely close the file. If I try to open the file for the second time, the applications crashes (can't open). Does anyone know how to completely close the file.
And this is not the actually code, just a summary of what I want to do:
FILE* f;
fopen_s(&f, "test.txt", "r");
// read file and edit data
fclose(f);
f = 0;
fopen_s(&f, "test.txt", "w");
fprintf(f, "%c", data);
fclose(f);
fclose() closes the file. It doesn't half close it. The notion of "completely closing" a file doesn't exist. A file is either open or closed. There's no in-between.
Although in your code you're using fopen_s() to open the file. I've no idea what that function is. I assume it works like fopen(), but instead of returning a FILE pointer, it instead stores it in its argument.
So the answer to your question is: to "completely" close a file, use fclose(). As you already do. That means the problem you're having lies elsewhere.

C Programming fopen() while opening a file

I've been wondering about this one. Most books I've read shows that when you open a file and you found that the file is not existing, you should put an error that there's no such file then exit the system...
FILE *stream = NULL;
stream = fopen("student.txt", "rt");
if (stream==NULL) {
printf(“Cannot open input file\n”);
exit(1);
else {printf("\nReading the student list directory. Wait a moment please...");
But I thought that instead of doing that.. why not automatically create a new one when you found that the file you are opening is not existing. Even if you will not be writing on the file upon using the program (but will use it next time). I'm not sure if this is efficient or not. I'm just new here and have no programming experience whatsoever so I'm asking your opinion what are the advantages and disadvantages of creating a file upon trying to open it instead of exiting the system as usually being exampled on the books.
FILE *stream = NULL;
stream = fopen("student.txt", "rt");
if (stream == NULL) stream = fopen("student.txt", "wt");
else {
printf("\nReading the student list directory. Wait a moment please...");
Your opinion will be highly appreciated. Thank you.
Because from your example, it seems like it's an input file, if it doesn't exist, no point creating it.
For example if the program is supposed to open a file, then count how many vowels in it, then I don't see much sense of creating the file if it doesn't exist.
my $0.02 worth.
Argument mode:
``r'' Open text file for reading.
``r+'' Open for reading and writing.
``w'' Truncate file to zero length or create text file for writing.
``w+'' Open for reading and writing. The file is created if it does not
exist, otherwise it is truncated.
``a'' Open for writing. The file is created if it does not exist.
``a+'' Open for reading and writing. The file is created if it does not
exist.
Your question is a simple case. Read above description, when you call fopen(), you should decide which mode shall be used. Please consider why a file is not created for "r" and "r+", and why a file is truncated for "w" and "w+", etc. All of these are reasonable designs.
If your program expects a file to exist and it doesn't, then creating one yourself doesn't make much sense, since it's going to be empty.
If OTOH, your program is OK with a file not existing and knows how to populate one from scratch, then it's perfectly fine to do so.
Either is fine as long as it makes sense for your program. Don't worry about efficiency here -- it's negligible. Worry about correctness first.
You may not have permission to create/write to a file in the directory that the user chooses. You will have to handle that error condition.

Resources