fopen
始终尝试从工作路径加载文件。为了重现该错误,我编写了下面的演示代码:
#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
和一个目录d:\path2
。然后我将上面的代码编译为名为 D:\path1\myprogram.exe
.cd d:\path1
myprogram
程序会打印“成功!!”。cd d:\path2
..\path1\myprogram
程序将打印“无法打开文件some_file.dat
。错误代码 = 2”。我的问题是,无论我从哪里运行程序,如何成功打开文件。如果
fopen
无法做到这一点,是否有库可以做到这一点?
回复评论:
我知道
fopen
可以从绝对路径加载文件,但我想让我的程序可移植。
fopen
可以采用完整的、绝对的文件路径,或者,如果它获得不完整的路径,则必须假设该路径是相对;相对路径始终相对于当前工作目录。
简而言之,
fopen
,就像任何其他打开文件的工具一样,无法神奇地猜测你的意思是什么文件;它需要确切地知道应该在哪里寻找文件。
您可以像这样指定完整路径:
// ....
const char* file_name = "D:\\path1\\some_file.dat";
// ....
从您的评论来看,您的问题似乎是您在编译时不知道文件的确切完整路径;所以你可能想以某种方式从程序用户那里获取文件的路径;
执行此操作的一种典型方法是从命令行的参数中读取它:
#include<stdio.h>
int main(int argc, char** argv) {
FILE* my_file = NULL;
if (argc < 2) {
puts("You need to specify a filename!");
return 2;
}
errno_t errcode = fopen_s(&my_file, argv[1], "rb");
if (errcode != 0) {
printf("Cannot open the file `%s`. Error code = %d", argv[1], errcode);
}
else {
puts("Success!!");
}
return errcode;
}
跑步:
测试用例1:
> cd d:\path1
> myprogram some_file.dat
Success!!
测试用例2(相对):
> cd d:\path2
> ..\path1\myprogram ..\path1\some_file.dat
Success!!
测试用例2(绝对):
> cd d:\path2
> ..\path1\myprogram d:\path1\some_file.dat
Success!!
如果您的
some_file.dat
始终与您的程序位于同一文件夹中,则可以针对类似问题提供 other answers。
当然,您还可以将命令行指定的路径与硬编码的文件名组合起来,为此,如果您需要坚持使用 C 语言,请查看
sprintf
函数,或者例如std::ostringstream
如果您实际上可以按照标签建议使用 C++。
假设该文件与可执行文件位于同一文件夹中。
您可以使用传递给程序的
argv[0]
– 这是可执行文件名称。#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;
}
从控制台当前目录运行
argv[0] = test
fname = some_file.dat
从并行文件夹在控制台中运行
argv[0] = ..\temp\test
fname = ..\temp\some_file.dat
从 Windows 文件管理器运行
argv[0] = F:\TEMP\test.exe
fname = F:\TEMP\some_file.dat