Two processes writing on the same file - c

I know this is recipe for disaster. And I actually made it work using shared variables.
But it's homework, and teacher definitely wants us to put many processes writing to the same file using different file pointers. I've been trying all day with little success, but I just can't find why this fails.
I have approached the problem in the folowing way:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int status;
int process_count = 0;
do
{
int from = (n / np) * (process_count) + 1;
int to = (n / np) * (process_count + 1);
if (fork() == 0)
{
FILE *aux;
aux = fopen("./parciais.txt", "w");
fseek(aux, sizeof(int) * process_count, SEEK_SET);
int sum = 0;
int i = from;
while (i <= to)
{
int square = i * i;
sum += square;
i++;
}
long int where_am_i = ftell(aux);
printf("I am process %i writing %i on byte: %li\n", process_count, sum, where_am_i);
fwrite(&sum, sizeof(int), 1, aux);
fclose(aux);
exit(1);
}
else
{
wait(&status);
process_count++;
}
} while (process_count < np);
FILE *aux;
aux = fopen("./parciais.txt", "r");
int sum;
for (int i = 0; i <= np - 1; i++)
{
fseek(aux, sizeof(int) * i, SEEK_SET);
long int where_am_i = ftell(aux);
int read;
fread(&read, sizeof(int), 1, aux);
printf("I am reading %i at byte: %li\n", read, where_am_i);
sum += read;
}
}
I expected the output to be something such as:
I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 98021 at byte: 0
I am reading 677369 at byte: 4
I am reading 1911310 at byte: 8
But I get:
I am process 0 writing 98021 on byte: 0
I am process 1 writing 677369 on byte: 4
I am process 2 writing 1911310 on byte: 8
I am reading 0 at byte: 0
I am reading 0 at byte: 4
I am reading 1911310 at byte: 8
This means, for some reason, only the last value is written.
I've been banging my head on the wall over this and I just can't find where's the catch... Can someone please lend me a hand?

The problem is due to fopen("./parciais.txt", "w") :
"w" : "Creates an empty file for writing. If a file with the same name already exists, its content is erased and the file is considered as a new empty file."
Try with "a" instead!
("Appends to a file. Writing operations, append data at the end of the file. The file is created if it does not exist.")
As mentioned in another answer, the "a" argument is not enough either. The file must be created once, hence in the main process, and then accessed in "r+b" mode for the fseek to work correctly!

As #B.Go already answered, the main problem is that you are opening the file with mode "w", which truncates it to zero length if it already exists. Each child process does this, clobbering the contents written by the previous one.
You want this combination of behaviors for the file:
it is created if it does not already exist (or I suppose you want this, at least)
it is not truncated upon opening if it does already exist
you may write to it
writes start at the current file offset, as opposed to automatically going to the current end of the file
the file is binary, not subject to any kind of character translation or to tail truncation upon writing to it
Unfortunately, there is no standard mode that provides all of it: the various r modes require that the file already exist, the w modes truncate the file if it does already exist, and the a modes direct all writes to the current end of the file, regardless of the stream's current offset. If you can assume that the file will already exist then mode "r+b", which can also be spelled "rb+", has all the wanted characteristics except creating the file if it doesn't exist:
aux = fopen("./parciais.txt", "r+b");
That permits reading as well, but just because you can read from the file doesn't mean you have to do. Additionally, on Linux and POSIX-conforming systems, there is no distinction between binary and text files, so you can omit the b if you are confident that your program needs to run only on POSIX systems. That you are using fork() suggests that this condition may apply to you.
If you must provide for creating the file, too, then open it once at the very beginning of the program, using any of the w or a modes depending on whether you want to truncate the file, then immediately close it again:
FILE *aux = fopen("./parciais.txt", "a");
if (aux) {
fclose(aux);
} else {
// handle error ...
}

Related

Append Random Text without Repetition for File (C)

I have 5 list of name
char *name[] = {"a","b","c","d","e"};
and I have 3 files
char path1[PATH_MAX+1]
snprintf(path1, PATH_MAX+1, "%sfile1.txt",dirname);
FILES *filename1 = fopen(path1, "w")
.
.
.
char path3[PATH_MAX+1]
snprintf(path3, PATH_MAX+1, "%sfile3.txt",dirname);
FILES *filename3 = fopen(path3, "w")
What I want is to randomly append a,b,c,d,e (one of them per file) into three of those files without repetition.
What I have right now is (example from one of them)
srand(time(NULL));
int one = rand()%5;
char path1[PATH_MAX+1];
snprintf(path1, PATH_MAX+1, "%sfile1.txt",dirname);
FILES *filename1 = fopen(path1, "w");
fputs(name[one],filename1);
fclose(filename1);
However, sometimes it is still possible where my file1.txt and file3.txt both contain b (same alphabet from name)
Questions
Did I miss something to make sure that all the random result always unique?
Is it also efficient tho to have 6 lines of code to create one file and append a random name inside it? I'm just wondering if I have to create like 20 files, I will write 120 lines that basically almost the same, just different in number (filename1 to filename3)
Thank you.
To get a unique sequence of characters, you can draw them from a diminishing pool. For example, after you have picked the a, it is removed from the pool. Of course, the pool must be at least as big as the number of files you want to print.
A simple way to implement this sort of picking is to pick a char from the pool, move the last character from the pool to the place of the picked character and decrease the pool size by one.
If you see a lot of repetition of code, especially if the only difference is a variable name along the lines of filename1, filename2, filename3 and so on should ring a bell that you should use an array: FILE *file[NFILE]. Be aware, though, that you can only have a certain number of files open at a time.
In your case, you want to write a single character to a file. There's no need to have multiple file s open simultaneously: Open a file, pick a char, write it to the file, close e file. Then process the next file.
The program below does what you want, I think.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define NFILES 10
int main()
{
char pool[] = "abcdefghij"; // Available chars as array
int npool = sizeof(pool) - 1; // Pool size minus terminating '\0'
int i;
if (npool < NFILES) {
fprintf(stderr,
"Not enough letters in pool for %d files.\n", NFILES);
exit(1);
}
srand(time(NULL));
for (i = 0; i < NFILES; i++) {
int ipick = rand() % npool; // position of pick
char pick = pool[ipick]; // picked char
char fname[20];
FILE *f;
pool[ipick] = pool[--npool]; // remove pick from pool
snprintf(fname, sizeof(fname), "file-%03d.txt", i);
f = fopen(fname, "w");
if (f == NULL) {
fprintf(stderr, "Could not create %s.\n", fname);
exit(1);
}
fprintf(f, "%c\n", pick);
fclose(f);
}
return 0;
}

How to check if file exists and create new file in C

I am new to programming in C and I am programming for the Raspberry Pi using a C compiler. All I want to be able to do is create a function that takes a String as a parameter and save it as a text file in a specific location. I want to check that file location to see what files exist and save the new file to that folder with an increment of 1 added to the file name.
For example, folder contains:
TestFile1
TestFile2
And I want to be able to create the new file saved as TestFile3.
This is the code that I have so far and want to know if I am on the right lines and get any tips please:
void WriteToFile(unsigned char *pID)
{
printf("Writing to file. . . . .\n");
/* Checking to see how many files are in the directory. */
int *count = 0;
DIR *d;
struct dirent *dir;
d = opendir("table_orders");
if(d)
{
while((dir = readdir(d)) != NULL)
{
printf("%s\n", dir->d_name);
count = count + 1; // Adds 1 to count whenever a file is found.
}
closedir(d);
}
char str[sizeOf(count)]; // Creates string.
sprintf(str, "%d", count); // Formats count integer into a string.
File *f = fopen("table_orders/Order " + str + ".txt", "a"); // Creates new file.
if(f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
fprintf(f, "Order: %s \n", pID);
fclose(f);
printf("The Order %s has been written to the file\n", pID);
}
int fd = open( "filename", O_RDWR | O_CREAT | O_EXCL, 0644 );
Nothing else is atomic - another process can create the file in between any check for existence and your actual creation of the file.
You can use stat (_stat in Windows) to see if a file exits. If it fails with errno set to ENOENT then the file doesn't exist. access is another possibility.
Of course it's not atomic, some other process could create the file in between your check and your call to fopen.
You are close, but so far off the mark, I think you need to put this on hold. Read some c tutorials with structured examples.
You have an algorithm error when you read through the directory and arbitrarily increase count. The logic should be more like
parse dir->name to 3 tokens "Testfile" 0001 ".log"
Using atoi or similar convert the numeral string to an int
When you declare str there's a lack of understanding of sizeof, it should read more like
char str[25];
This is enough to hold all digits of a 4 byte int as a string. sizeof count will be 4 probably,4 bytes 32 bits.
When you fopen you do something like "Dir/file" + str + ".log"
This isn't how you do this, + is mathematical in c. You need to use strcat or sprintf into a new work string, created and freed on the fly.
When appending a number to a file like here it makes sense to precede short numbers with 0 s . This produces regular filenames which have a good ls order.
Should you need to control create and exclusivity, you'll need to use open to open the file and fdopen it to a FILE type file handle.
When you go live with this you will need to prevent another process causing timing errors with scheduling use semaphores or a ".lock" file.
You will also want some maintenance routine to delete old logs and subsequently renumber all the remaining logs from 001
PS don't know why the down votes

C program over-writing file contents in if statement

I have a C program that is trying to record something called an "avalanche size". The criteria for recording this is if the "delta_energy" which is generated by the program is less than equal to zero then I can increment my avalanche size by "*avalanche_size = *avalanche_size + 1;" and if the delta_energy is not less than equal to zero then it continues running the loop without incrementing the avalanche size.
So what I want to do is to write the delta energy WHEN THE AVALANCHE SIZE IS INCREMENTED (not otherwise) to a file called delta_energies_GSA as shown in the code below.
But I what I find to happen is that if I put the fprintf statement inside the if{ } where the avalanche size is incremented for sure, everytime it does one iteration, it over-writes all the entries in the file. So in the end I end up with the file containing only the delta energies for one of the iterations. If I take the fprintf statemenet and put it outside the bracket, it records everything but it also gives me the delta energies for when the avalanche size is not incremented and I don't want those.
I thought about doing maybe a condition like "if the avalanche size is bigger than the previous avalanche size then fprintf the delta energy" ... but I'm not sure how to do this since avalanche size is just an integer not a vector..
Any help would be really appreciated! Thank you
for (k = 0; k < n_nodes; k++)
{
if (delta_energy <= 0.0)
{
stored_state[i] = new_state;
*avalanche_size = *avalanche_size + 1;
printf("\n\n For k = %d: ",k);
printf("\n\n This is the delta energy with GSA for %d avalanche size:%f", *avalanche_size, delta_energy);
fprintf(delta_energies_GSA,"\n %d\t %d\t %f \n",k, *avalanche_size, delta_energy);
}
I haven't shown the full code because its a very large function of a very large program.
I have also been very careful about when I open and close the file. The file is opened right at the beginning of the function after I have declared my variables. And I close the file right before the function ends.
This is how the file is opened:
{
double d_energy, q_A_minus_1, one_over_q_A_minus_1, prob_term;
neighbor_inf *np;
extern int generate_new_state();
FILE *delta_energies_GSA;
delta_energies_GSA = fopen("delta_energies_GSA.dat", "w");
if (delta_energies_GSA == NULL)
{
printf("I couldn't open delta_energies_GSA.dat for writing.\n");
exit(0);
}
Right after declaring my variables and it is closed before the function ends:
fclose(delta_energies_GSA);
return(stored_state);
} /* end recover_stored_patterns_GSA() */
The fprintf() does exactly what you want to do, append a string to a file, I don't see anything wrong here with your code if the fopen() is outside the for loop (in this case use "w+" with fopen, for append) and there aren't seek to 0.
EDIT
My wrong, not "w+" but "a" for append (and if you don't need to also read the file).
The wrong behavior that you must investigate is "why the fprintf replace the whole file".
Try this simple test.
#include <stdio.h>
int main(int argc, char **argv) {
FILE *f = fopen("test", "w");
if (f) {
int i;
for (i=0; i<100; i++) {
if (i % 3)
fprintf(f, "%d\n", i);
}
fclose(f);
}
return 0;
}

Read and write to binary files in C?

Does anyone have an example of code that can write to a binary file. And also code that can read a binary file and output to screen. Looking at examples I can write to a file ok But when I try to read from a file it is not outputting correctly.
Reading and writing binary files is pretty much the same as any other file, the only difference is how you open it:
unsigned char buffer[10];
FILE *ptr;
ptr = fopen("test.bin","rb"); // r for read, b for binary
fread(buffer,sizeof(buffer),1,ptr); // read 10 bytes to our buffer
You said you can read it, but it's not outputting correctly... keep in mind that when you "output" this data, you're not reading ASCII, so it's not like printing a string to the screen:
for(int i = 0; i<10; i++)
printf("%u ", buffer[i]); // prints a series of bytes
Writing to a file is pretty much the same, with the exception that you're using fwrite() instead of fread():
FILE *write_ptr;
write_ptr = fopen("test.bin","wb"); // w for write, b for binary
fwrite(buffer,sizeof(buffer),1,write_ptr); // write 10 bytes from our buffer
Since we're talking Linux.. there's an easy way to do a sanity check. Install hexdump on your system (if it's not already on there) and dump your file:
mike#mike-VirtualBox:~/C$ hexdump test.bin
0000000 457f 464c 0102 0001 0000 0000 0000 0000
0000010 0001 003e 0001 0000 0000 0000 0000 0000
...
Now compare that to your output:
mike#mike-VirtualBox:~/C$ ./a.out
127 69 76 70 2 1 1 0 0 0
hmm, maybe change the printf to a %x to make this a little clearer:
mike#mike-VirtualBox:~/C$ ./a.out
7F 45 4C 46 2 1 1 0 0 0
Hey, look! The data matches up now*. Awesome, we must be reading the binary file correctly!
*Note the bytes are just swapped on the output but that data is correct, you can adjust for this sort of thing
There are a few ways to do it. If I want to read and write binary I usually use open(), read(), write(), close(). Which are completely different than doing a byte at a time. You work with integer file descriptors instead of FILE * variables. fileno will get an integer descriptor from a FILE * BTW. You read a buffer full of data, say 32k bytes at once. The buffer is really an array which you can read from really fast because it's in memory. And reading and writing many bytes at once is faster than one at a time. It's called a blockread in Pascal I think, but read() is the C equivalent.
I looked but I don't have any examples handy. OK, these aren't ideal because they also are doing stuff with JPEG images. Here's a read, you probably only care about the part from open() to close(). fbuf is the array to read into,
sb.st_size is the file size in bytes from a stat() call.
fd = open(MASKFNAME,O_RDONLY);
if (fd != -1) {
read(fd,fbuf,sb.st_size);
close(fd);
splitmask(fbuf,(uint32_t)sb.st_size); // look at lines, etc
have_mask = 1;
}
Here's a write: (here pix is the byte array, jwidth and jheight are the JPEG width and height so for RGB color we write height * width * 3 color bytes). It's the # of bytes to write.
void simpdump(uint8_t *pix, char *nm) { // makes a raw aka .data file
int sdfd;
sdfd = open(nm,O_WRONLY | O_CREAT);
if (sdfd == -1) {
printf("bad open\n");
exit(-1);
}
printf("width: %i height: %i\n",jwidth,jheight); // to the console
write(sdfd,pix,(jwidth*jheight*3));
close(sdfd);
}
Look at man 2 open, also read, write, close. Also this old-style jpeg example.c: https://github.com/LuaDist/libjpeg/blob/master/example.c I'm reading and writing an entire image at once here. But they're binary reads and writes of bytes, just a lot at once.
"But when I try to read from a file it is not outputting correctly." Hmmm. If you read a number 65 that's (decimal) ASCII for an A. Maybe you should look at man ascii too. If you want a 1 that's ASCII 0x31. A char variable is a tiny 8-bit integer really, if you do a printf as a %i you get the ASCII value, if you do a %c you get the character. Do %x for hexadecimal. All from the same number between 0 and 255.
I'm quite happy with my "make a weak pin storage program" solution. Maybe it will help people who need a very simple binary file IO example to follow.
$ ls
WeakPin my_pin_code.pin weak_pin.c
$ ./WeakPin
Pin: 45 47 49 32
$ ./WeakPin 8 2
$ Need 4 ints to write a new pin!
$./WeakPin 8 2 99 49
Pin saved.
$ ./WeakPin
Pin: 8 2 99 49
$
$ cat weak_pin.c
// a program to save and read 4-digit pin codes in binary format
#include <stdio.h>
#include <stdlib.h>
#define PIN_FILE "my_pin_code.pin"
typedef struct { unsigned short a, b, c, d; } PinCode;
int main(int argc, const char** argv)
{
if (argc > 1) // create pin
{
if (argc != 5)
{
printf("Need 4 ints to write a new pin!\n");
return -1;
}
unsigned short _a = atoi(argv[1]);
unsigned short _b = atoi(argv[2]);
unsigned short _c = atoi(argv[3]);
unsigned short _d = atoi(argv[4]);
PinCode pc;
pc.a = _a; pc.b = _b; pc.c = _c; pc.d = _d;
FILE *f = fopen(PIN_FILE, "wb"); // create and/or overwrite
if (!f)
{
printf("Error in creating file. Aborting.\n");
return -2;
}
// write one PinCode object pc to the file *f
fwrite(&pc, sizeof(PinCode), 1, f);
fclose(f);
printf("Pin saved.\n");
return 0;
}
// else read existing pin
FILE *f = fopen(PIN_FILE, "rb");
if (!f)
{
printf("Error in reading file. Abort.\n");
return -3;
}
PinCode pc;
fread(&pc, sizeof(PinCode), 1, f);
fclose(f);
printf("Pin: ");
printf("%hu ", pc.a);
printf("%hu ", pc.b);
printf("%hu ", pc.c);
printf("%hu\n", pc.d);
return 0;
}
$
This is an example to read and write binary jjpg or wmv video file.
FILE *fout;
FILE *fin;
Int ch;
char *s;
fin=fopen("D:\\pic.jpg","rb");
if(fin==NULL)
{ printf("\n Unable to open the file ");
exit(1);
}
fout=fopen("D:\\ newpic.jpg","wb");
ch=fgetc(fin);
while (ch!=EOF)
{
s=(char *)ch;
printf("%c",s);
ch=fgetc (fin):
fputc(s,fout);
s++;
}
printf("data read and copied");
fclose(fin);
fclose(fout);
I really struggled to find a way to read a binary file into a byte array in C++ that would output the same hex values I see in a hex editor. After much trial and error, this seems to be the fastest way to do so without extra casts. By default it loads the entire file into memory, but only prints the first 1000 bytes.
string Filename = "BinaryFile.bin";
FILE* pFile;
pFile = fopen(Filename.c_str(), "rb");
fseek(pFile, 0L, SEEK_END);
size_t size = ftell(pFile);
fseek(pFile, 0L, SEEK_SET);
uint8_t* ByteArray;
ByteArray = new uint8_t[size];
if (pFile != NULL)
{
int counter = 0;
do {
ByteArray[counter] = fgetc(pFile);
counter++;
} while (counter <= size);
fclose(pFile);
}
for (size_t i = 0; i < 800; i++) {
printf("%02X ", ByteArray[i]);
}
this questions is linked with the question How to write binary data file on C and plot it using Gnuplot by CAMILO HG. I know that the real problem have two parts: 1) Write the binary data file, 2) Plot it using Gnuplot.
The first part has been very clearly answered here, so I do not have something to add.
For the second, the easy way is send the people to the Gnuplot manual, and I sure someone find a good answer, but I do not find it in the web, so I am going to explain one solution (which must be in the real question, but I new in stackoverflow and I can not answer there):
After write your binary data file using fwrite(), you should create a very simple program in C, a reader. The reader only contains the same structure as the writer, but you use fread() instead fwrite(). So it is very ease to generate this program: copy in the reader.c file the writing part of your original code and change write for read (and "wb" for "rb"). In addition, you could include some checks for the data, for example, if the length of the file is correct. And finally, your program need to print the data in the standard output using a printf().
For be clear: your program run like this
$ ./reader data.dat
X_position Y_position (it must be a comment for Gnuplot)*
1.23 2.45
2.54 3.12
5.98 9.52
Okey, with this program, in Gnuplot you only need to pipe the standard output of the reader to the Gnuplot, something like this:
plot '< ./reader data.dat'
This line, run the program reader, and the output is connected with Gnuplot and it plot the data.
*Because Gnuplot is going to read the output of the program, you must know what can Gnuplot read and plot and what can not.
#include <stdio.h>
#include <stdlib.h>
main(int argc, char **argv) //int argc; char **argv;
{
int wd;
FILE *in, *out;
if(argc != 3) {
printf("Input and output file are to be specified\n");
exit(1);
}
in = fopen(argv[1], "rb");
out = fopen(argv[2], "wb");
if(in == NULL || out == NULL) { /* open for write */
printf("Cannot open an input and an output file.\n");
getchar();
exit(0);
}
while(wd = getw(in), !feof(in)) putw(wd, out);
fclose(in);
fclose(out);
}

fwrite() does not override text in Windows (C)

I write this C code so that I could test whether fwrite could update some values in a text file. I tested on Linux and it works fine. In Windows (vista 32bits), however, it simply does not work. The file remains unchanged after I write a different byte using: cont = fwrite(&newfield, sizeof(char), 1, fp);
The registers are written on the file using a "#" separator, in the format:
Reg1FirstField#Reg1SecondField#Reg2FirstField#Reg2SecondField...
The final file should be: First#1#Second#9#Third#1#
I also tried putc and fprintf, all with no result. Can someone please help me with this?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct test {
char field1[20];
char field2;
} TEST;
int main(void) {
FILE *fp;
TEST reg, regread;
char regwrite[22];
int i, cont, charwritten;
fp=fopen("testupdate.txt","w+");
strcpy(reg.field1,"First");
reg.field2 = '1';
sprintf(regwrite,"%s#%c#", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
strcpy(reg.field1,"Second");
reg.field2 = '1';
sprintf(regwrite,"%s#%c#", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
strcpy(reg.field1,"Third");
reg.field2 = '1';
sprintf(regwrite,"%s#%c#", reg.field1, reg.field2);
cont = (int)strlen(regwrite);
charwritten = fwrite(regwrite,cont,1,fp);
fflush(fp);
fclose(fp);
// open file to update
fp=fopen("testupdate.txt","r+");
printf("\nUpdate field 2 on the second register:\n");
char aux[22];
// search for second register and update field 2
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^#]#", aux);
printf("%d-1: %s\n", i, aux);
if (strcmp(aux, "Second") == 0) {
char newfield = '9';
cont = fwrite(&newfield, sizeof(char), 1, fp);
printf("written: %d bytes, char: %c\n", cont, newfield);
// goes back one byte in order to read properly
// on the next fscanf
fseek(fp,-1,SEEK_CUR);
}
fscanf(fp,"%22[^#]#", aux);
printf("%d-2: %s\n",i, aux);
aux[0] = '\0';
}
fflush(fp);
fclose(fp);
// open file to see if the update was made
fp=fopen("testupdate.txt","r");
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^#]#", aux);
printf("%d-1: %s\n", i, aux);
fscanf(fp,"%22[^#]#",aux);
printf("%d-2: %s\n",i, aux);
aux[0] = '\0';
}
fclose(fp);
getchar();
return 0;
}
You're missing a file positioning function between the read and write. The Standard says:
7.19.5.3/6
When a file is opened with update mode, both input and output may be performed on the associated stream. However, ... 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. ...
for (i = 0; i < 3; i ++) {
fscanf(fp,"%22[^#]#", aux); /* read */
printf("%d-1: %s\n", i, aux);
if (strcmp(aux, "Second") == 0) {
char newfield = '9';
/* added a file positioning function */
fseek(fp, 0, SEEK_CUR); /* don't move */
cont = fwrite(&newfield, sizeof(char), 1, fp); /* write */
I didn't know it but here they explain it:
why fseek or fflush is always required between reading and writing in the read/write "+" modes
Conclusion: You must either fflush or fseek before every write when you use "+".
fseek(fp, 0, SEEK_CUR);
// or
fflush(fp);
cont = fwrite(&newfield, sizeof(char), 1, fp);
Fix verified on Cygwin.
You're not checking any return values for errors. I'm guessing the file is read-only and is not even opening properly.
At least here on OSX, your value 9 is begin appended to the end of the file ... so you're not updating the actual register value for Second at it's position in the file. For some reason after the scan for the appropriate point to modify the values, your stream pointer is actually at the end of the file. For instance, running and compiling your code on OSX produced the following output in the actual text file:
First#1#Second#1#Third#1#9
The reason your initial read-back is working is because the data is being written, but it's at the end of the file. So when you write the value and then back-up the stream and re-read the value, that works, but it's not being written in the location you're assuming.
Update: I've added some calls to ftell to see what's happening to the stream pointer, and it seems that your calls to fscanf are working as you'd assume, but the call to fwrite is jumping to the end of the file. Here's the modified output:
Update field 2 on the second register:
**Stream position: 0
0-1: First
0-2: 1
**Stream position: 8
1-1: Second
**Stream position before write: 15
**Stream position after write: 26
written: 1 bytes, char: 9
1-2: 9
**Stream position after read-back: 26
Update-2: It seems by simply saving the position of the stream-pointer, and then setting the position of the stream-pointer, the call to 'fwrite` worked without skipping to the end of the file. So I added:
fpos_t position;
fgetpos(fp, &position);
fsetpos(fp, &position);
right before the call to fwrite. Again, this is on OSX, you may see something different on Windows.
With this:
fp=fopen("testupdate.txt","w+");
^------ Notice the + sign
You opened the file in "append" mode -- that is what the plus sign does in this parameter. As a result, all of your fwrite() calls will be relative to the end of the file.
Using "r+" for the fopen() mode doesn't make sense -- the + means nothing in this case.
This and other issues with fopen() are why I prefer to use the POSIX-defined open().
To fix your particular case, get rid of the + characters from the fopen() modes, and consider that you might need to specify binary format on Windows ("wb" and "rb" modes).

Resources