Read and write in place not writing? - c

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.

Related

What is an update stream in C?

At n1256 7.19.5.2 paragraph 2 (with my bold):
If stream points to an output stream or an update stream in which the most recent
operation was not input, the fflush function causes any unwritten data for that stream
to be delivered to the host environment to be written to the file; otherwise, the behavior is
undefined.
If there was not the word 'update stream', the whole paragraph would make sense. But I don't know what it is. Standard itself doesn't introduce it. Google search doesn't seem to work. What's the meaning of it?
The term "update stream" simply means a stream that is both readable and writable.
This is specified in §7.19.5.3 point 3 (link, bold mine):
#include <stdio.h>
FILE *fopen(const char * restrict filename,const char * restrict mode);
[...]
The argument mode points to a string. If the string is one of the following, the file is open in the indicated mode. Otherwise, the behavior is undefined(237).
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(237)
r+b or rb+: open binary file for update (reading and writing)
w+b or wb+: truncate to zero length or create binary file for update
a+b or ab+: append; open or create binary file for update, writing at end-of-file
(237) If the string begins with one of the above sequences, the implementation might choose to ignore the remaining characters, or it might use them to select different kinds of a file (some of which might not conform to the properties in 7.19.2).
The term "update" in this context means a file opened for both reading and writing.
The term is used in the specification of the fopen function in section 7.19.5.3 of the C99 standard:
3 The argument mode points to a string.If the string is one of the following, the file is open in the indicated
mode.Otherwise, the behavior is undefined.
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
r+b or rb+ open binary file for update (reading and writing)
w+b or wb+ truncate to zero length or create binary file for update
a+b or ab+ append; open or create binary file for update, writing at end-of-file
...
6 When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), 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. Opening(or creating) a text file with update mode may instead open (or create) a binary stream in some implementations

C - Using fgetc on a write file

Say we have a file pointer like this:
FILE *output = fopen("test.out", "w");
After writing to it, I want to read it using fgetc
However when I do:
char c1 = fgetc(output);
and then I print out c1 I get that c1 equals -1 which means there was an error in fgetc. Is it because I opened the file using "w"?
How can I read and write from the same file in the same function?
If you want to be able to both read and write the file, you should open it in write/update mode (ie pass “w+” to the mode argument instead of just “w”)
Also be sure to do a frewind() or fseek() before trying to read from the file, otherwise you’ll be trying to read past the end of the file’s data.
You can't read from a write-only file. Open the file for read/write access using "w+" instead.
Also, after you write to the file, you have to seek backwards with fseek() before you can then read what you previously wrote.

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.

fprintf() function in C is not working properly

I wrote this code to input a number from a user and output it to a file .But its is not working ,after running the code the output.txt file is still empty.
Please tell me where I have done wrong .
I assure that I have created the output.txt file before running the program so the
file pointer will not be NULL.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
FILE *ptr;ptr=fopen("output.txt","rw");
if(ptr==NULL){printf("Error in oppening file aborting .......");exit(0);}
char ch[100];
scanf("%s",ch);
fprintf(ptr,"%s",ch);
fclose(ptr);
return 0;
}
From fopen documentation, the supported access modes are:
"r" read: Open file for input operations. The file must exist.
"w" write: Create an empty file for output operations. If a file with
the same name already exists, its contents are discarded and the file
is treated as a new empty file.
"a" append: Open file for output at the end of a file. Output
operations always write data at the end of the file, expanding it.
Repositioning operations (fseek, fsetpos, rewind) are ignored. The
file is created if it does not exist. "r+" read/update: Open a file
for update (both for input and output). The file must exist.
"w+" write/update: Create an empty file and open it for update (both
for input and output). If a file with the same name already exists its
contents are discarded and the file is treated as a new empty file.
"a+" append/update: Open a file for update (both for input and output)
with all output operations writing data at the end of the file.
Repositioning operations (fseek, fsetpos, rewind) affects the next
input operations, but output operations move the position back to the
end of file. The file is created if it does not exist.
In your code you use "rw" which is invalid and that's the reason your program doesn't work.
Change "rw" to "w" and your program will work. Note that you don't need to create output.txt, fopen will create it for you if your current user has write privileges in program's directory.

End of FILE* pointer is not equal to size of written data

Very simply put, I have the following code snippet:
FILE* test = fopen("C:\\core.u", "w");
printf("Filepointer at: %d\n", ftell(test));
fwrite(data, size, 1, test);
printf("Written: %d bytes.\n", size);
fseek(test, 0, SEEK_END);
printf("Filepointer is now at %d.\n", ftell(test));
fclose(test);
and it outputs:
Filepointer at: 0
Written: 73105 bytes.
Filepointer is now at 74160.
Why is that? Why does the number of bytes written not match the file pointer?
Since you're opening the file in text mode, it will convert end-of-line markers, such as LF, into CR/LF.
This is likely if you're running on Windows (and you probably are, given that your file name starts with "c:\").
If you open the file in "wb" mode, I suspect you'll find the numbers are identical:
FILE* test = fopen("C:\\core.u", "wb");
The C99 standard has this to say in 7.19.5.3 The fopen function:
The argument mode points to a string. If the string is one of the following, the file is
open in the indicated mode. Otherwise, the behaviour is undefined.
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
r+b or rb+ open binary file for update (reading and writing)
w+b or wb+ truncate to zero length or create binary file for update
a+b or ab+ append; open or create binary file for update, writing at end-of-file
You can see they distinguish between w and wb. I don't believe an implementation is required to treat the two differently but it's usually safer to use binary mode for binary data.
what does fwrite return? normally the return value should be the number of bytes written.
Also, what does the ftell() answer with right before the fseek?
It might help to know what operating system, C compiler version and C library.
A filepointer is a cookie. It has no value. The only thing you can use it for is to seek to the same place in a file. I'm not even sure if ISO C guarantees that ftell returns increasing values. If you don't believe this, please look at the different seek() modes. They exist precisely because the position is not a simple byte offset.
windows doesn't actually write all data out to the file without a flush and possibly an fsync. Maybe that's why

Resources