I have a code where I'm accessing a binary file several times. Each time I call the function, it opens the file for reading and it reads out only the required number of bytes (say n bytes each time).
The binary file contains time series data, and what I'd like it to be able to do is run the function call through a loop, and every time I call the function to open the same file, it needs to read out the next chunk of data, i.e, I don't want the file pointer to be reset every time. Is there a way to do this?
The function looks like so:
int readBinary(float *binImage, int gelements) {
imageFile = fopen("tmpImageFile", "r");
if (imageFile == NULL) {
fprintf(stderr, "Error opening file\n");
return (1);
}
fread(binImage, sizeof(float), gelements, imageFile);
return 0;
}
And in my main code, I'd like to run it through a loop, giving it the array binImage of size gelements every time. I'd rather not give it an array of size gelements * nLoop if that's avoidable.
The quick rules of thumb are
"Life gets easier if you properly separate responsibilities between functions"
and
"Life gets complicated if you use static or global variables".
In this case, giving the readBinary function both the responsibility of managing the FILE and reading the data is too much.
Note that the function doesn't close the handle.
If the handle is a local static in the function then it will be impossible to close it.
It also means that the function will be forever locked into using only "tmpImageFile" (which is not immediately apparent from the function's signature or missing documentation)
If the handle is a global then it may be possible to close it prematurely.
Notice that if you remove the "open file" responsibility the readBinary function is just a call to fread.
The best way to handle this is to skip the readBinary function altogether.
You say you have a caller which reads data in a loop.
Make this caller responsible for opening the FILE, use fread directly in the loop and close the file when you are done.
Now, this might give the caller too much responsibility. Simply have the caller accept the FILE* as a parameter and give the file management responsibility to its caller.
Or the caller's caller's caller, depending on where it makes sense to manage the file's lifetime.
Use a static variable so you retain the file pointer:
int readBinary(float *binImage, int gelements) {
static FILE *imageFile = NULL;
if (imageFile == NULL) {
imageFile = fopen("tmpImageFile", "r");
if (imageFile == NULL) {
perror("Error opening file: ");
return (1);
}
}
fread(binImage, sizeof(float), gelements, imageFile);
return 0;
}
I would pass the FILE* as parameter to function:
int readBinary(float *binImage, int gelements, FILE *imageFile) {
int bytes = fread(binImage, sizeof(float), gelements, imageFile);
return bytes != -1 ? 0 : 1;
}
I also added simple check for fread return value and converting it to your return value convention. Though this function seems so simple, you could just call fread directly, unless you want to add stuff like error print to it.
You can make the file pointer static and initialize it to NULL. Then next time onwards if it is not NULL, then it contains the opened file. Also while closing the file, make sure you make it to NULL again. Same can be done with a global pointer also
int readBinary(float *binImage, int gelements) {
static imageFile = NULL;
if(imageFile == NULL ) imageFile = fopen("tmpImageFile", "r");
if (imageFile == NULL) {
fprintf(stderr, "Error opening file\n");
return (1);
}
fread(binImage, sizeof(float), gelements, imageFile);
return 0;
}
Related
This question already has answers here:
How to change value of variable passed as argument?
(4 answers)
Closed 5 years ago.
I want to create the function that opens a file and then other functions use this opened file. This is my code,
#include <stdio.h>
int openFile(FILE* inputFile)
{
inputFile = fopen("input.txt", "r");
if (inputFile != NULL)
return 0;
else
return -1;
}
void readWholeFile(FILE* inputFile)
{
char str[20];
while (feof(inputFile)) {
fscanf(inputFile, str);
printf("%s\n", str);
}
}
int main() {
FILE* inputFile;
if (openFile(inputFile) == 0) {
readWholeFile(inputFile);
}
else
printf("File didn't open");
fclose(inputFile);
return 0;
}
"File didn't open" is not printed so the file should be opened but actually readWholeFile prints nothing as a file would be empty. What's the problem?
Your prototype makes no sense, openFile() can't change the caller's FILE * when it's passed by value, you need to pass the address of the pointer in that case:
int openFile(FILE **inputFile)
{
*inputFile = fopen("input.txt", "rt");
return *inputFile == NULL ? -1 : 0;
}
But of course this serves very little purpose, just use fopen() directly where you want to open a file, instead. Returning the pointer to the open file is easier to work with, instead of having to manage a separate int that carries no added value or information (an int being 0 or -1 is not "better" than a pointer being NULL or not NULL).
You should return inputFile itself. That wauy you can reused it from other function.
Also why pass that FILE* to openFile function? It's redundant.
Design-wise you can pass the filename and the parameters like r,w etc.
FILE* openFile(const char*name, const char*params)
{
inputFile = fopen(name, params);
if (inputFile != NULL)
return inputFile;
else
return NULL;
}
But in doing that you are just abstracting out the fopen() call. You still have to check the return value of openFile(). You can use double pointer and achieve the same thing but yes I have provided with an alternative.
FILE *inputFile = openFile("input.txt","r");
if( !inputFile ){
//...
}
The thing is as far as the method shown this is really doing anything other than wrapping the fopen() call. What you can get to know from this answer that you can pass the pointer around in Functions and how to use it.
Other answer provides how you use the double pointer but do you get what happened in previous case?
You are changing the local variable that is passed to openFile(). You change it. And when the function completes then that local variable is not there anymore. It's value wont affect the FILE* variable in main().
To be clear you don't need this method to open a file. It's better if you use the 2 lines alone. Because there is no improvement whatsoever. You still have to check the return value just like you would have in case of direct fopen call.
I have a doubt dealing with pointers in C.
During my program execution I must open and close a configuration file but since a different program updates its content i must do this several times while the program runs. So i made a little function which reads the file and closes it and i call it every time I need it.
int readConfigFile()
{
FILE* pfile = fopen("path to file", "r");
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
rewind(pFile);
text = (char*)malloc(sizeof(char) * lSize);
if (text == NULL) {
fputs("Memory error", stderr);
return (0);
}
if (fread(text, 1, lSize, pFile) <= 0) {
printf("Nothing read");
return 0;
}
text[lSize] = '\0';
//Do the actual reading
}
If i am not mistaken this functions creates a new FILE* pointer every time it runs however I was wondering if using a FILE* pointer with a larger scope and recycling it every time the function runs would be better. Meaning:
FILE* globalVaraible;
int readConfigFile(FILE* pFile)
{
*pfile = fopen("path to file", "r");
//Do some stuff here
}
I am worried that, since there is no garbage collector in C++ as far as i know, the first function will create too many FILE* pointers ,if runs for long enough, and overflow my memory. On the other hand having a global pointer, that will open and close in the context of a single function, seems rather wasteful and not very modular, at least for my point of view.
So should I recycle my pointer, or any reference for that matter, or is it okay to declare new ones as needed?
Thanks in advance.
You could use freopen().
http://en.cppreference.com/w/cpp/io/c/freopen
There is no guarantee that it will actually reuse dynamic memory allocated for the "old" file. This function may as well be a wrapper for fclose() and fopen() - it's all implementation defined.
From what I see, newlib (a popular libc for embedded targets) reuses the FILE storage, so there's a small gain here. Whether or not it makes a noticeable difference is another matter.
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=newlib/libc/stdio/freopen.c;h=fb1f6c4db3f294f672d7e6998e8c69215b7482c1;hb=HEAD
Ok, here is the deal...i remember creating a program past week that required me to open a file in binary mode and write data to it. At first, i tried using the fopen function, checking if the result is ok, then try to write data. I remember that at first try, the fwrite operation wasn't working. Then, after moving declaration of variables from a place to another, i was finally able to make the fwrite to insert data to the file.
Now, i need to create another similar program to do some other stuff, so i wanted to use the same allocation code (actually, i wanted to create a specific function to do the same), and here is what i was able to come up with:
#include <stdio.h>
int openfile(FILE *main, char *name, int option);
int main(void)
{
FILE *main;
int header_init;
int result;
switch (openfile(main,"main_file.bin",1)) {
case 1:
header_init = -1;
//fseek(main,0,SEEK_SET); --> useless
fwrite(&header_init,sizeof(int),1,main);
printf("ftell = %d\n",ftell(main)); break;
case 2:
fread(&header_init,sizeof(int),1,main);
printf("%d\n",header_init); break;
default:
printf("Error trying to open file\n");
}
printf("header_init is %d\n",header_init);
fclose(main); exit(0);
}
int openfile(FILE *main, char *name, int option)
{
int result_alloc;
int F_OK;
if (result_alloc = access (name, F_OK) != 0) {
printf("File not found, allocating a new one\n");
if ((main= fopen(name,"w+b")) != NULL) return 1;
}
else {
printf("File exist, allocating as r+b\n");
if ((main= fopen(name,"r+b")) != NULL) return 2;
}
printf("Failure trying to open");
return 0;
}
For some unfortunate reason, the fwrite operation is not writing -1 to the allocated file. My intention with this program is so that it will always check for existence of that specific file: if there is one in place, simply open it with r+b to allow update functions without overwriting the actual file contents. Otherwise, allocate a new one with a header value of -1 (i will use this file as a record file with chained list structure).
Seriously, i cannot understand why this is not working. The idea is the same of my previous program. The only thing that changed is that i created a function, because this is going to happen me later (because of the 3rd parameter that will allow me to reduce my code and make it more "readable" - at least this is the intention!). I HAVE to admit that i have some attention to details problem, but i am working hard to get better at it, i am probably missing something stupid in this code, but after hours looking at it i really wanted to ask here for some help. Thanks
Edit: I am running it under z/Linux. What i am trying to understand is, why the code above doesn't write -1 to the file, but the one below writes ok?
#include <stdio.h>
int main(void)
{
FILE *main;
int result_alloc;
int header_init;
int F_OK;
if (result_alloc = access ("test.bin", F_OK) != 0) {
printf("File not found, allocating a new one\n");
if ((main = fopen("test.bin","w+b")) == NULL) {
printf("Failure trying to open file");
return 1;
}
else {
header_init = -1;
printf("current pos is: w+b %d\n",ftell(main));
fwrite(&header_init,sizeof(int),1,main);
printf("current pos is: write header_init %d\n",ftell(main));
}
}
else {
if ((main = fopen("test.bin","r+b")) == NULL) {
printf("Failure trying to open file");
return 2;
}
else {
printf("current pos is: r+b %d\n",ftell(main));
fread(&header_init,sizeof(int),1,main);
printf("current pos is: read header_init %d\n",ftell(main));
}
}
}
The main issue that the assignment to the main variable inside of the openfile function is not seen by the calling function. Because C is pass by value, you're only changing the value of the function parameter, not the value of the variable that was passed in. So when openfile returns, the main variable inside of the main function is unchanged.
What you need to do is pass the address of that variable to the function, then within the function you dereference the local variable (which is a pointer) and assign a value to the dereferenced variable.
Also, it's not a good idea to have a variable with the same name as a function as it hides the function in that scope and can cause confusion.
So you would define your function as follows:
int openfile(FILE **fp, char *name, int option);
You would then call it like this (changing the name of the main variable to fp):
FILE *fp;
...
openfile(&fp,"main_file.bin",1)
Then inside of openfile, you dereference fp to change the value in the calling function:
*fp = fopen(name,"w+b")
The reason why the second code sample is working is that you're assigning directly to a local variable and then using that same variable later on in the function.
Also, you're "lucky" that the second piece of code is working because you did this:
int F_OK;
F_OK is already defined in unistd.h, where access() is defined. So by doing this you're redeclaring it and not giving it a value, causing undefined behavior. Get rid of this definition, and #include <unistd.h>, and the call to access() is guaranteed to work as expected.
What I'm trying to do is to write a function that creates a file, fills it with data and returns the file to main(). The question is - what is the right way to "return file". Should I pass pointer / file descriptor or just disregard all this and use filename?
EDIT: doing the right way (I hope):
int mkrandfile(const char *name, int range, int qnt)
{
FILE *afile;
int i = 0;
if (afile = fopen(name, "w+"))
{
while((i <= qnt) && fprintf(afile, "%d ", rand() % range - range/2))
i++;
fclose(afile);
if (i != qnt + 1)
return -2;
}
else
return -1;
}
You are correct that returning afile from that function is wrong. Once the file is closed, that file handle is no longer valid. Use of it by the caller would result in undefined behavior.
While it is probably not the best idea from a modularity standpoint, you could leave the file open and then return the handle. But I think one of the following might be better:
Pass in an opened file handle to the function (let the caller open and close it).
Make the caller open the file again on its own.
The first option may be more efficient when file caching by the OS (if applicable here) is considered.
I'm trying to print to a text file numerous variables yet it doesn't work.
I checked and verified that i write it in the correct syntax.
I also checked the return value and it's positive therefore i know it did write to the file, however when i open the file it's empty.
I would be happy for some help.
This is the code:
I initiate DynsaleDayPtr in the main:
FILE* DynsaleDayPtr = CreateTextFiles("sale_day.txt");
Create function:
FILE* CreateTextFiles (char* fileName)
{
FILE* saleFilePtr=NULL;
if((saleFilePtr=fopen(fileName,"a+"))==NULL)
printf("File couldn't be opened\n");
return saleFilePtr;
}
The call to the function TextAddSale is done from a function that is called in the main:
TextAddSale(DynSaleDayPtr,dynNumOfRecords);
Bool TextAddSale (FILE* DynsaleDayPtr, int* dynNumOfRecords)
{
char id[6];
char name [50];
char priceChar[20];
char* tmp = NULL;
int price=-1;
DynamicRecord * newRec=NULL;
scanf("%s%s%s",id,name,priceChar);
newRec = (DynamicRecord *)malloc(sizeof(DynamicRecord));
if (newRec == NULL)
return False;
tmp = (char*)malloc(strlen(name)+1);
if (tmp == NULL)
{
free (newRec);
return False;
}
strcpy(tmp,name);
newRec->productName = tmp;
strcpy(newRec->productId, id);
newRec->productPrice=atoi (priceChar);
if (fprintf(DynsaleDayPtr,"%d %s %s %d", strlen(newRec->productName),
newRec->productId, newRec->productName, newRec->productPrice)>0)
{
*dynNumOfRecords=(*dynNumOfRecords)+1;
return True;
}
}
thanks!
You need to flush the stream.
fflush(FILE*);
Of course, you have to close the stream if you have done with it.
fclose(FILE*);
Agree with #pmg - try something like this:
FILE *pFile = fopen("foo.txt","w");
if (pFile==NULL)
bad();
fprintf(pfile,"Hello world\n");
fclose(pfile);
make that work first - then fix whatever's wrong in the big app -
A thought:
scanf("%s%s%s",id,name,priceChar);
the above statement is a bit dodgy since you haven't said how many bytes
should go in each string.
better to use fgets() then parse the string retrieving the individual values
or create a better format specifier.
If the above statement causes a memory overwrite the rest of your program
could malfunction causing things like what you describe.
fprintf() most likely uses buffered output. Therefore, you should either fflush() the DynSaleDayPtr stream or, better yet, print a newline to the file. The latter has the added benefit of making the file contents actually readable...
Also, don't forget to close() the stream when you're finished with writing. This will also render fflush() unnecessary.