fopen
always tries to load files from the working path. To reproduce the bug, I wrote a demo code below:
#include<stdio.h>
int main(void) {
FILE* my_file = NULL;
const char* file_name = "some_file.dat";
errno_t errcode = fopen_s(&my_file, file_name, "rb");
if (errcode != 0) {
printf("Cannot open the file `%s`. Error code = %d", file_name, errcode);
}
else {
puts("Success!!");
}
return errcode;
}
d:\path1\some_file.dat
and a directory d:\path2
. Then I compile the code above to the program named D:\path1\myprogram.exe
.cd d:\path1
myprogram
and the program will print "Success!!".cd d:\path2
..\path1\myprogram
and the program will print "Cannot open the file some_file.dat
. Error code = 2".My question is how to successfully open the file no matter where I run my program from. If fopen
can't do this, is there a library that can do it?
Reply to the comments:
I know that fopen
can load files from absolute paths but I want to make my program portable. myprogram.exe
and some_file.dat
are always in the same path.
Assuming that the file is in the same folder as the executable.
You can use the argv[0]
passed to the program – which is the executable name.
I have shown it run three ways: two from the console, and one from GUI file manager.
#include <stdio.h>
#include <string.h>
#define SLASH_CHAR '\\' // Windows
//#define SLASH_CHAR '/' // Linux
int main(int argc, char *argv[]) {
const char* file_name = "some_file.dat"; // desired filename
printf("argv[0] = %s\n", argv[0]); // the executable
// allocate enough memory to create a file name
char *fname = malloc(strlen(argv[0]) + strlen(file_name) + 1);
if(fname == NULL)
return 1;
// find the last path separator in the executable (if any)
char *slash_ptr = strrchr(argv[0], SLASH_CHAR);
if (slash_ptr == NULL) {
// just use the file name
strcpy(fname, file_name);
}
else {
// create a new file name
strcpy(fname, argv[0]);
size_t slash_ind = slash_ptr - argv[0];
strcpy(fname + slash_ind + 1, file_name);
}
printf("fname = %s\n", fname);
free(fname);
getchar();
return 0;
}
Run from the console current directory
argv[0] = test
fname = some_file.dat
Run in the console from a parallel folder
argv[0] = ..\temp\test
fname = ..\temp\some_file.dat
Run from Windows file manager
argv[0] = F:\TEMP\test.exe
fname = F:\TEMP\some_file.dat