I'd like to save a struct in a file.
I'd like to realize a function which makes this work.
I tried this code but it didn't work.
struct utilisateur // enregestrement pour sauvegarder les details de l utilisateur
{
char nom[20];
char prenom[20];
int place;
char depart[20];
char arrive[20];
char sexe;
int nwagon;
};
struct utilisateur utilis;
struct utilisateur *Table[48];
void crea_fich(struct utilisateur *Tutilis)
// creation un fichier, vous introduiez le nom, et le sotcker par enreg
{
FILE *f;
if (f!==0)
{
printf("error in the name of file \n");
exit(1);
}
if (f=fopen(futilis,"w")==Null){
fprint("We can't creat file \n");
exit(1);
}
else{
f=fopen("futilis.dat","wb");
fwrite(Tutilis ,sizeof(utilisateur),1,f);
}
}
No. You need to write out your data members individually, one at a time. You should not just blindly copy the memory representation of your struct into the file output buffer (which it is clear you are trying to do). Writing files that way will cause the files to non-portable (they won't be readable except on the platform that they were written), because of the endian-ness and the platform-specific padding of the struct elements.
Try this, and then if that's not doing what you want, try explaining how it differs from what you want.
void crea_fich(struct utilisateur *Tutilis)
{
FILE *f;
size_t nwritten;
f = fopen("futilis.dat","wb");
if (f == NULL)
{
fprintf(stderr, "Cannot open file for writing.\n");
exit(1);
}
nwritten = fwrite(Tutilis, sizeof Tutilis[0], 1, f);
fclose(f);
if (nwritten < 1)
{
fprintf(stderr, "Writing to file failed.\n");
exit(1);
}
}
Michael S is right; using fwrite with a struct is wildly nonportable. But let's assume you don't care about that and you want something easy to write that will work.
The problem in your code is that you've broken the Golden Rule of sizeof: never use sizeof with a type name. Instead you should use sizeof with an lvalue, and almost always with the dereference of another argument. Thus
Tutilis = malloc (sizeof (*Tutilis));
...
fwrite(Tutilis, sizeof (*Tutilis), 1, f);
If you follow this recipe it's much harder to get the size wrong.
Just a simple example :)
// your struct
struct Data
{
int first;
double second;
char third[10];
};
Then write the struct!
struct Data data = {22, 4.0, "Hi"};
FILE* output;
output = fopen("Data.dat", "wb");
fwrite(&data, sizeof(data), 1, output);
fclose(output);
Finally read the data from the file you created!
struct Data data;
FILE* input;
input = fopen("Data.dat", "rb");
fread(&data, sizeof(data), 1, input);
// you got the data from the file!
fclose(input);
Binary files are nightmares if not written and read wisely. You have to take care of a lot of things about the architecture where the file was created and where will it be read. Endianess and size of variables are the most important. Also, If you have pointers inside your struct, the pointer that will be written to the file not the actual data where the pointer points to. Sorry, I didn't edit your code because it is full of compilation errors :)
I deleted my first answer because it was so wrong, sorry :)
I realize this is an old post, but it comes up when people search for this information, so I'll give my own solution.
This is basically what I have used in one of my games. I actually have some extra library specific code in my own function for dialogs, but this is essentially it. I write data individually. I don't think I have a struct for this data, but there is no difference, just write your individual struct members separately. As mentioned, it's better this way.
// returns 1 if successful, 0 if not
int savemap(const char *map_name)
{
FILE *file = NULL;
// open the file in write binary mode
file = fopen(map_name, "wb");
// always check return values to see if it was opened okay
if(file == NULL) {
fprintf(stderr, "Error opening file for writing.\n");
return 0;
}
// write file ID, version and pills
fwrite(MAP_ID, sizeof(char), strlen(MAP_ID)+1, file);
fwrite(&MAP_VER, sizeof(unsigned char), 1, file);
fwrite(&pills, sizeof(unsigned short), 1, file);
// write the map data (unsigned int map[315])
fwrite(&map, sizeof(unsigned int), 315, file);
// never forget to close the file
fclose(file);
return 1;
}
I'd look over the symbol names first, like NULL and fprint, not to mention that weird \0. As an additional thought, you should close the file after writing to make sure it gets flushed to disk, and double check that futilis variable is a char* that contains a valid, writeable path.
Related
I find this code in a website:
struct person
{
int id;
char fname[20];
char lname[20];
};
int main ()
{
FILE *outfile;
// open file for writing
outfile = fopen ("person.dat", "w");
struct person input1 = {1, "rohan", "sharma"};
// write struct to file
fwrite (&input1, sizeof(struct person), 1, outfile);
if(fwrite != 0)
printf("contents to file written successfully !\n");
return 0;
}
Is line if(fwrite != 0) correct?
Does we can compare function name itself(fwrite)?
What is value of fwrite in this case?
No, that's definitely not the correct way to do it. The correct way is this:
if(fwrite(&input1, sizeof(struct person), 1, outfile)) != 1) {
/* Error writing */
}
But in order to avoid duplicate magic numbers, this would be better:
size_t num = 1;
if(fwrite(&input1, sizeof(struct person), num, outfile)) != num) {
I find it hard to believe ANY site would publish rubbish code like that. I knew geeksforgeeks isn't very trustworthy, but this was incredibly bad. It's wrong on so many levels.
if(fwrite != 0) is a completely pointless check. If fwrite != 0 would evaluate to false, it would mean that the function call to fwrite would fail. The check basically means "Is fwrite a null pointer?" And if a library function is a null pointer, then something is REALLY wrong.
fwrite returns the number of elements written, which in this case should be one element.
I wrote a rant about Tutorialspoint earlier, but now I need to add geeksforgeeks to my list of resources I recommend to stay far, far away from.
I want to implement a function in my program that sends a .txt to my email with some tasks that i have to do in the day. Here's the code:
void txtCreator(){
/**file.dat and file.txt, respectively**/
FILE *fp, *fp1;
/**struct that contain the events**/
struct evento *display = (struct evento *)malloc(sizeof(struct evento));
char buffer[48];
char email_events[] = {"dd_mm.txt"};//filename.txt
char msg[]={"Nao ha eventos disponiveis para hoje!\n"};
int count=0;
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
strftime(buffer, 48, "%d_%m", &timenow);
fp = fopen(file_name, "rb");
fp1 = fopen(email_events, "w");
if(strcmp(buffer, email_events)!=0){
strcpy(email_events, buffer);
while(fread(display, sizeof(struct evento), 1, fp)==1){
if (feof(fp) || fp==NULL){
break;
}
else if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1){
fwrite(display, sizeof(struct evento), 1, fp1);
fprintf(fp1, "%s", "\n");
count++;
}
}
}
if(count==0){
fprintf(fp1, "%s", msg);
}
fclose(fp);
fclose(fp1);
}
Everything is working just fine, but there's two problems:
1-
strcpy(email_events, buffer);
is not working, and:
2-
when i create the .txt file, it shows like that:
test ¹0(¹€(.v™ ™ °'¹8¹uguese_Brazil.12
it shows the event name (test) correctly, but the date is not working.
I've tried a lot of things, but nothing works.
Sorry for the bad english, not my native language.
when i create the .txt file, it shows like that:
test ¹0(¹€(.v™ ™ °'¹8¹uguese_Brazil.12
Let's address this first: you're not writing text to your .txt file. You're writing a struct. It's going to look like garbage.
For example, let's say display->dia is 19. This means the number 19 will be written to the file, not the text 19, the number 19. Read as text, 19 is garbage. 10 is a newline. 65 is A.
If your intent is to dump the structs into a file, assuming struct evento has no pointers, you're good. In fact you probably shouldn't add a newline, it will interfere with reading the file by the size of the struct.
If your intent is to produce a human readable text file, you need to translate each piece of the struct into text. For example, if you wanted to write the day and month as text...
fprintf(fp1, "%d_%d", display->dia, display->mes);
I'll assume that going forward.
strcpy(email_events, buffer); is not working
At first glance it looks like your strcpy is backwards, it's strcpy(src, dest) and presumably you want to copy email_events into buffer: strcpy(buffer, email_events).
Looking further, your code does nothing with either buffer nor email_events after that. The strcpy is pointless.
Going even further, buffer is the month and day like 07_19. email_events is always dd_mm.txt. Those will never match. strcmp(buffer, email_events)!=0 will always be true making the if check pointless.
I'm not sure what the intent of buffer and email_events are, but it appears to be trying to create a filename based on the current date? This can be done much simpler with one better named variable outfile.
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
char outfile[20];
strftime(outfile, 20, "%d_%m.txt", &timenow);
Moving along to other problems, you don't check that fp1 opened.
You do eventually check fp but you check it after you've already read from a possibly null file pointer. If you're compiling with an address sanitizer (which you should) it will cause an error. Causing an error when using a null pointer is good, it will solve many a mystery memory problem for you.
It's much easier and robust and address sanitizer friendly to check immediately. We can also do a better job naming them to avoid confusing the input from the output: in and out.
FILE *in = fopen(file_name, "rb");
if( in == NULL ) {
perror(file_name);
exit(1);
}
And since you're reading binary with rb you should be writing binary you should be using wb. This only matters on Windows, but might as well be consistent.
FILE *out = fopen(outfile, "wb");
if( out == NULL ) {
perror(outfile);
exit(1);
}
There's no need to check feof(fp), while(fread(display, sizeof(struct evento), 1, fp)==1) will already exit the loop at end of file when it fails to read. In general, explicitly checking for the end of file leads to subtle problems.
The read/write loop is now much simpler.
while(fread(display, sizeof(struct evento), 1, in)==1){
if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1) {
fprintf(out, "%d_%d\n", display->dia, display->mes);
count++;
}
}
Putting it all together...
void txtCreator(){
const char *no_events_found_msg = "Nao ha eventos disponiveis para hoje!\n";
// No need to cast the result of malloc, it just invites mistakes.
struct evento *display = malloc(sizeof(struct evento));
// Generate the output filename directly, no strcmp and strcpy necessary.
time_t rawtime;
time(&rawtime);
struct tm timenow = *localtime(&rawtime);
char outfile[20];
strftime(outfile, 48, "%d_%m.txt", &timenow);
// Immediatetly make sure the files are open and error immediately.
FILE *in = fopen(file_name, "rb");
if( in == NULL ) {
perror(file_name);
exit(1);
}
FILE *out = fopen(outfile, "wb");
if( out == NULL ) {
perror(outfile);
exit(1);
}
// Now that we know the files are open, reading and writing is much simpler.
int count=0;
while(fread(display, sizeof(struct evento), 1, in)==1){
if(display->dia==timenow.tm_mday && display->mes==timenow.tm_mon+1) {
fprintf(out, "%d_%d\n", display->dia, display->mes);
count++;
}
}
if(count==0){
fprintf(out, "%s", no_events_found_msg);
}
fclose(in);
fclose(out);
}
Note that I've used a style which declares variables in place. This makes the code easier to read, limits the scope of each variable, and it avoids declaring variables which you never use.
Assuming that you are meaning to copy email_events into your buffer (since you assigned a static string), your strcpy parameters are backwards.
Below is the declaration of strcpy
char *strcpy(char *dest, const char *src);
You probably meant:
strcpy(buffer, email_events);
int main()
{
int size = 512, i = 1;
char buffer[1000];
char *newFileTemp;
char const *chunk = "Chunk";
memset(buffer, 0, sizeof(buffer));
FILE *fb;
FILE *fp=fopen("blah.txt", "r");
if (fp == NULL)
{
perror("doesnt exist");
return 0;
}
fread(buffer,sizeof(char),sizeof(buffer), fp);
sprintf(newFileTemp, "%s%i", chunk, i);
printf("blah check %s",newFileTemp);
fb = fopen(newFileTemp, "wb");
if (fb == NULL)
{
perror("doesnt exist");
return 0;
}
fwrite(buffer, sizeof(char), sizeof(buffer), fb);
fclose(fp);
fclose(fb);
return 0;
}
I'm trying to use sprintf to create a new file named chunk1 that has the data of file blah.text (blah.txt is already created). But even though the code compiles properly, it doesn't create a new file. Please help.
What you are experiencing is called an undefined behaviour, because you are using newFileTemp before you have initialized it. To correct the problem, initialize it like this:
newFileTemp = (char*)malloc(100);
or declare it like this:
char newFileTemp[100];
The reason is that sprintf expects newFileTemp to have enough space allocated for storing the string it is formatting (it will not allocate it for you).
Also:
If you use malloc don't forget to free.
Don't forget to check the success of functions like fread and fwrite.
You'll have another problem later because in your call to fwrite you are trying to write always 1000 bytes (sizeof(buffer) is 1000 bytes), even if your file had fewer bytes. This is where the return value of fread comes into play (it returns the actual amount of bytes read): you need to use that return value instead of sizeof(buffer).
I created a function that is successfully reading the binary file but it is not printing as I wanted.
The function:
void print_register() {
FILE *fp;
fp = fopen("data.bin", "rb");
if (fp == NULL) {
error_message("Fail to open data.bin for reading");
exit(0);
}
reg buffer;
while (EOF != feof(fp)) {
fread(&buffer, sizeof(reg), 1, fp);
printf("%s %d %d\n", buffer.name, buffer.age, buffer.id);
}
fclose(fp);
}
Note: reg is a typedef for a struct:
typedef struct registers reg;
struct registers {
char name[30];
int age;
int id;
char end;
};
Function for writing the file:
void register_new() {
system("clear");
reg buffer;
FILE *fp;
fp = fopen("data.bin", "ab");
if (fp == NULL) {
error_message("Error opening file data.bin");
exit(0);
}
write_register(buffer);
fwrite(&buffer, sizeof(reg), 1, fp);
fclose(fp);
}
Posting a printscreen of what was print to be more helpful:
As you can see on image, after the "p" (command for printing) is where should be the name, age and id of the struct.
In register_new(), you have to send the address of buffer in order for write_register() to work properly (right now you're giving it a copy of buffer).
Replace:
write_register(buffer);
with:
write_register(&buffer);
Then correct write_register to take and work with an address instead of a structure.
This might help you understand what's going on: http://fresh2refresh.com/c-programming/c-passing-struct-to-function
Your reading loop is incorrect. Don't use feof(), it can only tell is you have reached the end of file after a read attempt failed and it might not return EOF anyway, it is only specified as returning 0 or non 0. Use this instead:
while (fread(&buffer, sizeof(reg), 1, fp) == 1) {
printf("%s %d %d\n", buffer.name, buffer.age, buffer.id);
}
fread returns the number of items successfully read. Here you request to read 1 item of size sizeof(reg), if the item was read successfully, fread will return 1, otherwise it will return 0 (in case of a read error or end of file reached).
Your screenshot shows a syntax error, which you seem to have fixed now. Remove that, it is not helping.
In your function register_new, you are writing an uninitialized structure reg to the file, no wonder it does not contain anything useful when you read it back from the file. And for what it is worth, opening this file in binary mode is the correct thing to do since it contains binary data, namely the int members of the structure.
The reg passed to fwrite is indeed uninitialized. write_register gets a copy of this uninitialized structure by value, and probably modifies this copy, but this does not affect the local structure in register_new. You should modify write_register() to take a pointer to the structure. Unlike C++, there is no passing by reference in C.
Hi guys i have a problem when I try to open a file. In a function when i try to read an existing text file, after i initialized the file pointer i still get the error "cannot open the file", this is the code:
FILE * fp;
fp = NULL;
fp=fopen("results.txt","r");
if(fp==NULL){
printf("error!");
exit(1);
}
using the debugger i can see the fp initialized to NULL, as requested. In the next order i can see its value changed to '0x751d9c68'.
So now it's not NULL, but the program still prints error.
PS: I used the same code to open another file in another program (that works): as always the initial value of fp is NULL, then it's changed to '0x751d9c68' (yes, it has the same value in both programs), but this time works, because fp is in fact different from NULL.
PPS: I'm using Codelite, if that helps.
EDIT: adding a printf("%p\n", fp); prints this "751D9C68"
Atleta * leggiRisultati (char fileName [], int * dim){FILE * fp; int count, i;
Atleta temp;
fp = NULL;
fp=fopen(fileName,"r");
printf("%p\n", fp);
if(fp==NULL){
perror("Error");
}
while (fscanf (fp, "%s%s%d%d%d", temp.cod, temp.nome, &temp.tN, &temp.tB, &temp.tC)== 5)
count ++;
rewind (fp);
Atleta * atl = (Atleta*) malloc(count * sizeof(Atleta));
for (i=0; i<count; i++){
int nr = fscanf(fp, "%s%s%d%d%d",atl[i].cod, atl[i].nome, &atl[i].tN, &atl[i].tB, &atl[i].tC);
//just controlling if the reading is done properly
if (nr < 4) {
printf ("cannot read the file %s",fileName);
exit (1);
}
} fclose(fp);
return atl;
}
I then use this function in this main
int main (){ int dim; Atleta * a; int i;
a = leggiRisultati("risultati.txt", &dim);
for (i =0; i<dim;i++){
stampaRisultato(a[i]);}
return 0;
}
Where "stampaRisultato" prints a line of the file just read and "Atleta" is a struct defined as:
typedef struct {
char cod[5];
char nome[21];
int tN, tB, tC;
}Atleta;
And last, yes the text file is in the same directory as my executable, yes I have the permission to open the file, the file contains a certain number of lines with 2 strings and 3 int each.
Your code should work, I can only think of 3 things that may cause this issue.
In my experience, it's oftentimes the simplist mistakes that get you, because you're so focused on the more complex elements that some things slip your mind. I can't see the rest of your program, so forgive me if any of these answers seem patronizing. Here are the first things I would check:
1.) file permissions. Make sure you're a user with permission to access and/or change the file in question. This is a pretty easy fix on linux, but I don't know about windows.
2.) file location. Make sure your text file is in the same directory as your executable. You'll need to do this if you don't specify file location.
3.) #include statements. Sometimes even the best of us get too excited to get into the bulk of our program, and we forget to include stdio.h and/or stdlib.h. If this is the case you may run into an issue where you set the file pointer to null, and then the fopen function doesn't run, so your pointer remains null.