提问人:ben 提问时间:11/15/2023 最后编辑:Chrisben 更新时间:11/15/2023 访问量:67
如何使用 MacOs 将输出文件保存到 c 中它所属的文件夹中
How do I save an output file to the folder it belongs to in c using MacOs
问:
该文件当前保存到 /Users/benreaby,而我希望它保存到可执行文件的源文件夹中
// Filename that I want to save to the source
// folder that the executable is located in
#define FILENAME "TACmFile.txt"
int main(int argc, const char * argv[]) {
fp = fopen(FILENAME, "w");
fprintf(fp, "hello world");
fclose(fp);
return 0;
}
答:
当运行可执行文件并使用相对文件路径时,文件 TACmFile.txt 将写入运行可执行文件时当前工作目录的任何位置。这不一定与源代码所在的目录有任何相似之处。
如果要覆盖它,则需要指定绝对路径。您可能需要从配置文件中读取可执行文件才能获取文件路径信息。
评论
argv[0]
这是一个解决方案。这取决于 argv[0] 中是否存在可执行文件路径和文件名。此处修改了代码以添加新函数 merge_pf(),该函数使用在 argv[0] 中找到的可执行文件的路径。它从路径中剥离可执行文件名称,并将所需的文件名追加到同一路径。这个新字符串可用于在程序目录中打开您选择的文件。
这段代码被我测试为win32。路径标记('/')是为Unix添加的 - 因此,也应该在那里工作 - 但未经过测试。在使用此代码之前,请测试/检查您的操作系统是否支持包含程序路径和文件名的 argv[0] 的关键原则:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* merge_pf() expects path to have exe name, ie: 'F:/dir/program.exe'.
Param fname is some filename, ie: 'file.txt'
Example final string would be: 'F:/dir/file.txt'
*/
char *merge_pf(const char *path, const char *fname)
{
int iii;
char *path_file = malloc(strlen(path)+strlen(fname)+1);
if(path_file)
{
strcpy(path_file, path);
iii=(int)strlen(path_file);
while(iii--)
{
if(path_file[iii]=='\\' || path_file[iii]=='/') /* DOS or Unix path token*/
break; /* Stop if we hit the last token */
path_file[iii]='\0'; /*strip .exe name from path*/
}
strcpy(&path_file[iii+1], fname); /* merge path and file name*/
}
return path_file;
}
// Filename that I want to save to the source
// folder that the executable is located in
#define FILENAME "TACmFile.txt"
int main(int argc, const char *argv[])
{
char *pf = merge_pf(argv[0], FILENAME);
FILE *fp;
if(pf)
{
printf("Will open: %s\n", pf);
fp = fopen(pf, "w");
if(fp)
{
fprintf(fp, "hello world");
fclose(fp);
}
free(pf);
}
return 0;
}
查看您的操作系统是否在 arv[0] 中具有程序路径和文件名的测试可能如下所示......(可能存在一种更安全的方法):
#include <stdio.h>
int main(int argc, const char *argv[])
{
const char *pf = argv[0];
if(pf)
{
printf("Program Path and File name: %s\n", pf);
}
return 0;
}
成功将如下所示:
Program Path and File name: f:/PROJECTS/32bit/_HELP/C/H118/math.exe
在每个 POSIX 系统中,当内核加载程序时,它会从指定为任何 exec*(2) 系统调用的第一个参数的文件加载到内存中。系统调用的不同变体通常实现不同的 API 和查找可执行文件的方法。
exec 系统调用的最通用格式要求您向其传递程序名称(文件系统上存在的文件的名称)、表示程序参数的字符串数组(包括其名称)以及表示程序环境的字符串数组。由于这三件事可以由程序任意指定,因此程序没有固定且可预测的方法来知道程序在文件系统中的位置,除非该信息由执行系统调用的进程传递给程序。argv
envp
exec(2)
例如,如果调用
execle("bin/program", "a", "b", "c", NULL, envp);
您将要求内核在当前工作目录下的目录中查找程序,但由于第 0 个参数是程序将收到一个由字符串“a”(程序名称)、“b”(第一个参数)和“c”(第二个参数)组成的参数列表,因此没有遵循确定程序调用方式的正常方法,并且不会告诉我们有关加载到内存中的文件的任何有用信息。由于环境也被指定,即使我们对参数有一些想法或访问权限,环境也是不同的,并且在调用的情况下,如下所示:"bin"
"a"
argv[0]
argv[0]
execle("program", "program", "a", "b", NULL, envp);
程序将无法使用环境变量找到程序的位置,因为用于搜索程序的环境变量与通过 exec() 调用传递的环境变量不同。PATH
PATH
如果幸运的话,shell 会告诉你一些事情(如果你运行一个好的 shell),因为它会自动向你传递导出的环境,以及用于调用程序的程序名称,因此你可以按照 shell 用来查找你的程序的相同算法,找到一个可执行文件,该文件可以被 但是仍然存在程序文件被重命名并且无法从该路径访问的竞争条件。exec()
综上所述,您可以检查该目录是否存在并使用该目录(但从最后一个“/”字符切入)并将其用作目录。argv[0]
在 linux 中,可以检查“/proc/self/cmd”以获取用于调用 exec 的文件名,但如果路径名是相对的(不存在“/”字符),并且变量已更改,您将无法遵循用于查找可执行文件的相同目录列表。PATH
exec()
通常,这不会失败,常见的过程包括检查字符串并尝试从该路径中提取可执行文件名,并将其用作要写入文件的目录的目录名称。这并不完全可靠,但在大多数情况下都有效。argv[0]
评论