在C语言中将文件写入用户的HOME目录

4

我正在尝试将一个 .txt 文件写入用户的 HOME 目录。

我已经尝试过:

char str[] = "TEST";
char* file = strcat(getenv("HOME"), "/dataNumbers.txt"); //I am concatenating the user's home directory and the filename to be created.
myFile = fopen(file,"w");
fwrite(str , 1 , sizeof(str) , myFile );

然而,这并不会创建文件。

  1. file 变量的值是什么?它是否是预期的文件名?
  2. 运行此代码的用户是否有写入 $HOME 的权限?你可能认为这应该是安全的假设,但你仍然应该双重检查该目录的权限。
- Code-Apprentice
如果它没有创建文件,你也不应该调用 fwrite()。这里明显缺乏错误检查。你需要测试 myFile 是否为 null,并在发现时调用 perror() 或其相关函数,而不是继续像没有问题一样进行。 - user207421
3个回答

6
您正在错误地使用 strcat 函数。
 char *file;
 char *fileName = "/dataNumbers.txt";

 file = malloc(strlen(getenv("HOME") + strlen(fileName) + 1); // to account for NULL terminator
 strcpy(file, getenv("HOME"));
 strcat(file, fileName);

file现在会包含连接的路径和文件名。

显然,这可以写得更加简洁。我只是想尽可能直接明了。


你的代码中缺少几个闭合括号,但是因为回答简单明了,我给你加1分。 - r3mainer
getenv("HOME") 后面应该有一个闭合括号。 - Christian Pao.

5

你不能使用strcat()函数来操作环境变量。你需要另一个缓冲区:

char file[256]; // or whatever, I think there is a #define for this, something like PATH_MAX
strcat(strcpy(file, getenv("HOME")), "/dataNumbers.txt");
myFile = fopen(file,"w");

编辑 为了解决下面的评论之一,您应该先确保要连接的数据不会溢出 file 缓冲区,或者动态分配它 - 不要忘记在之后释放它。


@LeeDanielCrocker 如果用户无法写入“用户主目录”,那么我发现很难甚至不可能将任何含义附加到它上面。这肯定是一个非问题。 - user207421
@DavidHoelzer 同意,但如果组合太长,则文件无法打开。 我的主要观点是不要将 strcat 用于环境变量。 - user207421
@EJP 这是假设程序在 他的 主目录下运行,而不是其他人的。这还假设存在一个主目录,在所有操作系统上这可能并不是一个好的假设。 - Lee Daniel Crocker
1
我应该澄清一下,这是为了学校项目而言的,这些预防措施可以被忽略。 - Hani Al-shafei
1
@LeeDanielCrocker getenv("HOME") 返回您自己的主目录。 - user207421
显示剩余7条评论

2
在C语言中,字符串与其他高级语言不同;也就是说,你必须手动分配所需的内存空间。在使用c-string函数时,需要确保已为结果字符串分配了足够的内存,通过在堆栈上预留足够的空间(即char filename [HOPEFULLY_ENOUGH])或通过堆(malloc()等)实现。您不能指望getenv返回一个足够的空间供您连接的字符串;以下是一个完整的程序,从头到尾完成您想要做的事情(除了一些啰嗦的错误检查):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void)
{
    char *filename = "/dataNumbers.txt";
    char *writeString = "TEST";
    char *home_dir = getenv("HOME");
    char *filepath = malloc(strlen(home_dir) + strlen(filename) + 1);
    strncpy(filepath, home_dir, strlen(home_dir) + 1);
    strncat(filepath, filename, strlen(filename) + 1);
    printf("%s\n", filepath);

    FILE *myFile = fopen(filepath, "w");
    fwrite(writeString, 1, strlen(writeString), myFile);
    fclose(myFile);
    free(filepath);
    return 0;
}

strncpy将复制字符串和空终止符(这就是+1的原因)。strncat将从空终止符处开始连接,结果连接的字符串本身必须以空终止符结尾(因此在strncat的第三个参数中使用+1)。

我使用malloc和free是因为很难精确知道文件完整路径的长度。你可以选择一个巨大的数组(如char[4096]),但这似乎很浪费,不是吗? malloc()允许您准确地保留所需的内存量。既不多,也不少。

您还可以使用snprintf函数进行字符串连接。我仅包含此内容供您个人丰富知识,有时拥有多种执行相同操作的方法很好,即使strcpy和strcat会使您的意图更清晰地传达给代码读者:

char *filename = "/dataNumbers.txt";
char *writeString = "TEST";
char *home_dir = getenv("HOME");
size_t size = strlen(home_dir) + strlen(filename) + 1;
char *filepath = malloc(size);
snprintf(filepath, size, "%s%s", home_dir, filename);

希望这能帮到你!

不要忘记释放(filepath) ; - Mikhail Zakharov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接