Thread: reading and writing data to a binary file

  1. #1
    Registered User
    Join Date
    Oct 2012
    Posts
    16

    reading and writing data to a binary file

    Hello all! First of all, happy thanksgiving!

    Secondly, I'm having an issue overwriting data in a binary file.. here's my code..

    Code:
    #include <stdlib.h>#include <stdio.h>
    #include <time.h>
    #include <string.h>
    
    
    typedef struct{    
    	int date;   
    	char c;
    }STR;
    
    
    void deleteData(char*, FILE*);
    
    
    main () {
    
    
    	FILE *data;
    	STR one, two, three, four, five, random = {0};
    	char deleteMe[128];
    
    
    	srand(time(NULL));
    
    
    	one.c = (rand() % 25) + 65;
    	one.date = rand() % 31;
    	two.c = (rand() % 25) + 65;
    	two.date = rand() % 31;
    	three.c = (rand() % 25) + 65;
    	three.date = rand() % 31;
    	four.c = (rand() % 25) + 65;
    	four.date = rand() % 31;
    	five.c = (rand() % 25) + 65;
    	five.date = rand() % 31;
    
    
    	data = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    	if (data == NULL){
    		printf("Unable to open file!");
    		exit(-1);
    	}
    
    
    	fwrite(&one, sizeof(STR), 1, data);
    	fwrite(&two, sizeof(STR), 1, data);
    	fwrite(&three, sizeof(STR), 1, data);
    	fwrite(&four, sizeof(STR), 1, data);
    	fwrite(&five, sizeof(STR), 1, data);
    
    
    
    
    	fclose(data);
    
    
    	printf("Displaying File: ex12struc.dat contents: \n\n");
    
    
    	data = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    
    
    	while(fscanf(data, "i", random.date) != EOF){
    		fread(&random, sizeof(STR), 1, data);
    		printf("%i\n", random.date);
    		printf("%c\n", random.c);
    		printf("\n");
    	}
    
    
    
    
    	fclose(data);
    
    
    	printf("Enter an integer or character you would like to DELETE from the file:");
    	scanf("%s", deleteMe);
    	printf("\n\n");
    	printf("%s\n", deleteMe);
    
    
    	deleteData(deleteMe, data);
    
    
    
    
    	system("pause");
    }
    
    
    void deleteData(char *deleteMe, FILE *fp){
    	char deleted[128];
    	STR random = {0};
    
    
    	fp = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    
    
    
    
    	while (fscanf(fp, "s", deleted) != EOF){
    		fread(&deleted, sizeof(STR), 1, fp);
    		if (deleted[0] == *deleteMe){
    			deleted[0] = 0;
    			fwrite(deleted, sizeof(deleted), 1, fp);
    		}
    		else if (*deleteMe == deleted[4]){
    			deleted[4] = 7;
    			fwrite(deleted, sizeof(deleted), 1, fp);
    
    
    		}}
    
    
    	fclose(fp);
    	fp = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    	printf("\n\n");
    	while(fscanf(fp, "s", deleted) != EOF){
    		fread(&random, sizeof(STR), 1, fp);
    		printf("%i\n", random.date);
    		printf("%c\n", random.c);
    		printf("\n");
    	}
    	fclose(fp);
    }
    In the deleteData function it compares the information fine, changes the value in deleted it goes over the write fine but then when I reprint the information nothing is changed. Any ideas?

  2. #2
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    I would give it a shot with only opening the file for reading with "rb". Then closing this stream . Then opening the file with "wb" for writing.Again i would close that stream.

  3. #3
    Registered User
    Join Date
    Oct 2012
    Posts
    16
    I tried doing that but for some reason opening it in "wb" erases all of the information. "r+b" is the only one that doesn't delete it.. I'll try it again though!

  4. #4
    SAMARAS std10093's Avatar
    Join Date
    Jan 2011
    Location
    Nice, France
    Posts
    2,694
    You mean overwrites them...This is what it is supposed to do

  5. #5
    Registered User
    Join Date
    Oct 2012
    Posts
    16
    Quote Originally Posted by std10093 View Post
    You mean overwrites them...This is what it is supposed to do
    Well it overwrites it with nothing, when it opens the file with "wb" for some reason it opens it with 0 bytes in the file.

    I figured out how to do part of the problem with this code

    Code:
    #include <stdlib.h>#include <stdio.h>
    #include <time.h>
    #include <string.h>
    
    
    typedef struct{    
    	int date;   
    	char c;
    }STR;
    
    
    void deleteData(STR, FILE*);
    
    
    main () {
    
    
    	FILE *data;
    	STR one, two, three, four, five, random = {0};
    	STR deleteMe = {0};
    	char pass = 0;
    
    
    	srand(time(NULL));
    
    
    	
    	one.c = (rand() % 25) + 65;
    	one.date = rand() % 31;
    	two.c = (rand() % 25) + 65;
    	two.date = rand() % 31;
    	three.c = (rand() % 25) + 65;
    	three.date = rand() % 31;
    	four.c = (rand() % 25) + 65;
    	four.date = rand() % 31;
    	five.c = (rand() % 25) + 65;
    	five.date = rand() % 31;
    
    
    	data = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    	if (data == NULL){
    		printf("Unable to open file!");
    		exit(-1);
    	}
    
    
    	fwrite(&one, sizeof(STR), 1, data);
    	fwrite(&two, sizeof(STR), 1, data);
    	fwrite(&three, sizeof(STR), 1, data);
    	fwrite(&four, sizeof(STR), 1, data);
    	fwrite(&five, sizeof(STR), 1, data);
    
    
    
    
    	fclose(data);
    
    
    	printf("Displaying File: ex12struc.dat contents: \n\n");
    
    
    	data = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    
    
    	while(fscanf(data, "i", random.date) != EOF){
    		fread(&random, sizeof(STR), 1, data);
    		printf("%i\n", random.date);
    		printf("%c\n", random.c);
    		printf("\n");
    	}
    
    
    
    
    	fclose(data);
    
    
    	printf("Enter 1 for integer or C for character mode!");
    	pass = getchar();
    	if (pass - 48 == 1){
    		printf("Enter the integer you want to DELETE: ");
    		scanf("%i", &deleteMe.date);
    		printf("\n\nYou entered %i.", deleteMe.date);
    	}
    
    
    	else if (pass == 67){
    		printf("Enter the character you want to DELETE: ");
    		scanf(" %c", &deleteMe.c);
    		printf("\n\nYou entered %c.", deleteMe.c);
    	}
    	
    	else if (pass == 99){
    		printf("Enter the character you want to DELETE: ");
    		scanf(" %c", &deleteMe.c);
    		printf("\n\nYou entered %c.", deleteMe.c);
    	}
    	else{
    		printf("You entered an invalid option!\n");
    		system("pause");
    		exit(-1);
    	}
    	printf("\n\n");
    	
    
    
    	deleteData(deleteMe, data);
    
    
    
    
    	system("pause");
    }
    
    
    void deleteData(STR deleteMe, FILE *fp){
    	char deleted[128];
    	STR random = {0};
    
    
    	
    	fp = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    	printf("\n\n");
    	while(fscanf(fp, "s", deleted) != EOF){
    		fread(&random, sizeof(STR), 1, fp);
    		if (random.date == deleteMe.date){
    		random.date = NULL;
    		printf("%i\n", random.date);
    		fwrite(&random, sizeof(STR), 1, fp);
    		}
    		else
    		printf("%i\n", random.date);
    		if (random.c == deleteMe.c){
    		random.c = NULL;
    		printf("%c\n", random.c);
    		}
    		else
    		printf("%c\n", random.c);
    		printf("\n");
    	}
    	fclose(fp);
    
    
    
    
    }

    My only issue is I can't figure out how to clear out the int number, it just replaces it with 0 and also for some reason when I input an integer to be deleted the variable AFTER the one that is "deleted" is skipped during the read operation.

    The character deletion works perfectly however. It clears out the value that I select and reads and prints them all.

  6. #6
    Registered User
    Join Date
    May 2010
    Posts
    4,631
    If you don't want to truncate the file contents when opening for writing then make sure you use an open mode that preserves the contents, like r+, a+. See the documentation for fopen() for a thorough explanation.

    Jim

  7. #7
    Registered User
    Join Date
    Oct 2012
    Posts
    16
    Quote Originally Posted by jimblumberg View Post
    If you don't want to truncate the file contents when opening for writing then make sure you use an open mode that preserves the contents, like r+, a+. See the documentation for fopen() for a thorough explanation.

    Jim
    yea I was using "r+b" or "rb+" fine but it doesn't seem to take the fwrite.

  8. #8
    Registered User
    Join Date
    May 2010
    Posts
    4,631
    Why are you mixing formatted output (fscanf) with unformatted output (fwrite)? I also suggest you study the documentation of fscanf(), you seem to be misusing the format specifier.


    Jim

  9. #9
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Code:
    main () {
    It's int main(void).

    Code:
    while(fscanf(data, "i", random.date) != EOF){
            fread(&random, sizeof(STR), 1, data);
    This way of reading the file doesn't work but you are lucky because your format string for fscanf() is missing the % before "i" and fscanf() doesn't read anything from the file.
    If fscanf() would read the integer (as I think you have intended) than the following fread() would read garbage because the file pointer is already on the character after the integer.
    You should put the fread()-call inside the while condition and forget about the fscanf().

    Code:
    if (pass - 48 == 1)
    Don't use magic numbers. Instead write this as
    Code:
    if (pass - '0' == 1)
    Code:
    void deleteData(STR deleteMe, FILE *fp){
    ...
    while(fscanf(fp, "s", deleted) != EOF){
        fread(&random, sizeof(STR), 1, fp);
        if (random.date == deleteMe.date){
            random.date = NULL;
            printf("%i\n", random.date);
            fwrite(&random, sizeof(STR), 1, fp);
        }
    for some reason when I input an integer to be deleted the variable AFTER the one that is "deleted" is skipped during the read operation.
    It's not just skipped but you have overwritten it.
    After fread() the file pointer is on the beginning of the following structure. Now you call fwrite() at this point, hence you are replacing the structure values with the values from "random" and the file pointer is moved forward to the beginning of the next structure.
    Just look at the contents of the file in a hex editor.

    The character deletion works perfectly however. It clears out the value that I select and reads and prints them all.
    Because you don't do anything to the file. You just print the new value on the screen.
    Again use a hex editor to see the contents after running your program.

    For example if I run your program with
    Code:
    $ ./foo
    Displaying File: ex12struc.dat contents: 
    
    5
    L
    
    21
    J
    
    27
    S
    
    29
    Q
    
    1
    F
    
    Enter 1 for integer or C for character mode!1
    Enter the integer you want to DELETE: 5
    
    
    You entered 5.
    
    
    
    0
    L
    
    27
    S
    
    29
    Q
    
    1
    F
    I get:
    Code:
    $ hd ex12struc.dat 
    00000000  05 00 00 00 4c af 04 08  00 00 00 00 4c af 04 08  |....L.......L...|
    00000010  1b 00 00 00 53 00 00 00  1d 00 00 00 51 8d 04 08  |....S.......Q...|
    00000020  01 00 00 00 46 31 14 00                           |....F1..|
    00000028
    The first structure has still the integer 5, but the second which should be 21 is now 0.

    Bye, Andreas

  10. #10
    Registered User
    Join Date
    Oct 2012
    Posts
    16
    Thanks for the help! I'll check everything out once I get home from work

  11. #11
    Registered User
    Join Date
    Oct 2012
    Posts
    16
    So this is where I'm at now. The program is still not changing the data in the .dat file.

    Code:
    #include <stdlib.h>
    #include <stdio.h>
    #include <time.h>
    #include <string.h>
    
    
    typedef struct{    
    	int date;   
    	char c;
    }STR;
    
    
    void deleteData(STR, FILE*);
    
    
    int main (void) {
    
    
    	FILE *data;
    	STR one, two, three, four, five, random = {0};
    	STR deleteMe = {0};
    	char pass = 0;
    	int size;
    
    
    	srand(time(NULL));
    
    
    	
    	one.c = (rand() % 25) + 65;
    	one.date = rand() % 31;
    	two.c = (rand() % 25) + 65;
    	two.date = rand() % 31;
    	three.c = (rand() % 25) + 65;
    	three.date = rand() % 31;
    	four.c = (rand() % 25) + 65;
    	four.date = rand() % 31;
    	five.c = (rand() % 25) + 65;
    	five.date = rand() % 31;
    
    
    	data = fopen("C:\\My Files\\ex12struc.dat", "wb");
    
    
    	if (data == NULL){
    		printf("Unable to open file!");
    		exit(-1);
    	}
    
    
    	fwrite(&one, sizeof(STR), 1, data);
    	fwrite(&two, sizeof(STR), 1, data);
    	fwrite(&three, sizeof(STR), 1, data);
    	fwrite(&four, sizeof(STR), 1, data);
    	fwrite(&five, sizeof(STR), 1, data);
    
    
    
    
    	fclose(data);
    
    
    	printf("Displaying File: ex12struc.dat contents: \n\n");
    
    
    	data = fopen("C:\\My Files\\ex12struc.dat", "r+b");
    
    
    
    
    	while (fread(&random, sizeof(STR), 1, data) != 0){
    		printf("%i\n", random.date);
    		printf("%c\n", random.c);
    		printf("\n");
    	}
    
    
    
    
    	fclose(data);
    
    
    	printf("Enter 1 for integer or C for character mode!");
    	pass = getchar();
    	if (pass - '0' == 1){
    		printf("Enter the integer you want to DELETE: ");
    		scanf("%i", &deleteMe.date);
    		printf("\n\nYou entered %i.", deleteMe.date);
    	}
    
    
    	else if (pass == 67){
    		printf("Enter the character you want to DELETE: ");
    		scanf(" %c", &deleteMe.c);
    		printf("\n\nYou entered %c.", deleteMe.c);
    	}
    	
    	else if (pass == 99){
    		printf("Enter the character you want to DELETE: ");
    		scanf(" %c", &deleteMe.c);
    		printf("\n\nYou entered %c.", deleteMe.c);
    	}
    	else{
    		printf("You entered an invalid option!\n");
    		system("pause");
    		exit(-1);
    	}
    	printf("\n\n");
    	
    
    
    	deleteData(deleteMe, data);
    
    
    
    
    	system("pause");
    }
    
    
    void deleteData(STR deleteMe, FILE *fp){
    	char deleted[128];
    	STR random = {0};
    	int null = 0;
    	long pos;
    
    
    	fp = fopen("C:\\My Files\\ex12struc.dat", "rb+");
    
    
    	printf("\n\n");
    	
    	while (fread(&random, sizeof(STR), 1, fp) != 0){
    		
    		if (random.date == deleteMe.date){
    		random.date = NULL;
    		fwrite(&random, sizeof(STR), 1, fp);
    		}
    		else
    		null++;
    
    
    		if (random.c == deleteMe.c){
    		random.c = NULL;
    		fwrite(&random, sizeof(STR), 1, fp);
    		}
    		else
    		null++;
    	}
    	if (null == 10){
    		printf("Value entered does not match any characters/integers!\nReload program and try again.\n\n");
    		system("pause");
    		exit(-1);
    	}
    	fclose(fp);
    
    
    	fp = fopen("C:\\My Files\\ex12struc.dat", "rb");
    
    
    	while(fread(&random, sizeof(STR), 1, fp) != 0){
    		
    		printf("%i\n", random.date);
    		printf("%c\n", random.c);
    		printf("\n");
    	}
    
    
    	fclose(fp);
    }

  12. #12
    Registered User
    Join Date
    May 2010
    Posts
    4,631
    When I try to compile your code I get the following errors and warnings:
    main.c||In function ‘main’:|
    main.c|23|warning: unused variable ‘size’ [-Wunused-variable]|
    main.c||In function ‘deleteData’:|
    main.c|136|error: assignment makes integer from pointer without a cast|
    main.c|144|error: assignment makes integer from pointer without a cast|
    main.c|125|warning: unused variable ‘pos’ [-Wunused-variable]|
    main.c|122|warning: unused variable ‘deleted’ [-Wunused-variable]|
    ||=== Build finished: 2 errors, 3 warnings ===|

    Jim

  13. #13
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Code:
    void deleteData(STR deleteMe, FILE *fp){
    ...
    while (fread(&random, sizeof(STR), 1, fp) != 0){
        if (random.date == deleteMe.date){
        random.date = NULL;
        fwrite(&random, sizeof(STR), 1, fp);
    }
    You have still the problem that you write the new data at the wrong position.

    The computer uses a file position indicator to mark the current position where the next operation will be executed. If you open a new file, this indicator is pointing to the beginning of the file. When reading parts of your file, the indicator will move along and will always point to the position after the parts you have read. If you then use fwrite() you will overwrite parts which follow the parts you have just read not the parts you have read!

    If you want to replace parts you have just read you have to either move the indicator back to the beginning of this block or you do all your modifications in memory (for example store the whole file in an array, modify some parts and then write out the new data overwriting the old file altogether).

    Bye, Andreas

  14. #14
    Registered User
    Join Date
    Oct 2012
    Posts
    16
    I thought about it last night after reading my book and came up with this solution.
    But it still isn't working perfectly.. so I'm still trying to debug it.

    Code:
    void deleteData(STR *deleteMe, FILE *fp){
    	char deleted[128];
    	STR random;
    	int null = 0;
    	long pos;
    	int i = 0;
    
    
    	fp = fopen("C:\\My Files\\ex12struc.dat", "rb+");
    
    
    	printf("\n\n");
    
    
    	while (fread(&random, sizeof(STR), 1, fp) != 0){
    
    
    		i++;
    		if (i <= 5){
    			pos = ftell(fp);
    			if (random.date == deleteMe->date){
    				random.date = NULL;
    				pos = pos - sizeof(STR);
    				fseek(fp, pos, SEEK_SET);
    				fwrite(&random, sizeof(STR), 1, fp);
    				if (i == 5){
    					break;}
    			}
    			else if (null <= 9)
    				null++;
    			else
    				break;
    
    
    			if (random.c == deleteMe->c){
    				random.c = NULL;
    				pos = pos - sizeof(STR);
    				fseek(fp, pos, SEEK_SET);
    				fwrite(&random, sizeof(STR), 1, fp);
    				if (i == 5){
    					break;}
    			}
    
    
    			else if (null <= 9)
    				null++;
    
    
    			else
    				break;
    		}
    		else
    			break;
    	}
    	if (null == 10){
    		printf("Value entered does not match any characters/integers!\nReload program and try again.\n\n");
    		system("pause");
    		exit(-1);
    	}
    	fclose(fp);
    
    
    	fp = fopen("C:\\My Files\\ex12struc.dat", "rb");
    
    
    	while(fread(&random, sizeof(STR), 1, fp) != 0){
    
    
    		printf("%i\n", random.date);
    		printf("%c\n", random.c);
    		printf("\n");
    	}
    
    
    	fclose(fp);
    }

  15. #15
    Registered User
    Join Date
    Oct 2012
    Posts
    16
    Alright I figured it out! I put an extra fseek after the write to manually position where it was pointing to after the initial read. Thanks for everyone's help! Now to clean up the code... wee fun.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. reading and writing to a binary file
    By greg677 in forum C Programming
    Replies: 2
    Last Post: 05-24-2010, 08:09 PM
  2. Writing binary data to a file
    By zacs7 in forum C Programming
    Replies: 5
    Last Post: 10-24-2007, 04:00 PM
  3. reading and writing to the end of a binary file
    By cloudy in forum C++ Programming
    Replies: 3
    Last Post: 06-06-2005, 04:03 PM
  4. Help with Reading and writing binary data
    By Yasir_Malik in forum C Programming
    Replies: 3
    Last Post: 12-12-2004, 09:24 AM
  5. Replies: 2
    Last Post: 12-16-2001, 09:09 PM