使用fopen创建所有所需的文件夹

23

我正在使用 fopen("aaa\bbb\ccc\myfile.txt","w") 来创建输出文件。但是文件夹 aaabbbccc 不存在。解决这个问题的最佳方法是什么?是否有任何标准方法可以要求 fopen() 创建所有需要的文件夹?


9
不,fopen 永远不会创建目录。已经有一个关于扩展的 mkdir() 可以创建多级目录的问题,并且有很好的答案,这与你想要的类似。你需要对 "aaa/bbb/ccc/" 进行多级 mkdir,然后调用 fopen - user2404501
2
对于Windows系统,您可以使用此帖子中的信息http://stackoverflow.com/questions/2834737/creating-new-folders-if-they-dont-exist-for-fopen - Alex Jones
3
记得一般情况下要将反斜杠加倍。虽然 fopen() 函数不支持创建目录,但如果目录存在,这将是必要的。 - unwind
@WumpusQ.Wumbley,为什么不回答问题而是发表评论呢?这样作者就可以关闭这个问题了。 - Jérôme Pouiller
文件夹是GUI工件。文件系统处理的是目录,它们是操作系统特定的。标准C11不了解目录。 - Basile Starynkevitch
7个回答

1

这里还有另一种用纯C编写的替代方案,不依赖于strtok(该函数会破坏传递的文件路径字符串):

const char pathSeparator =
#ifdef _WIN32
  '\\';
#else
  '/';
#endif

// Given a file path, create all constituent directories if missing
void create_file_path_dirs(char *file_path) {
  char *dir_path = (char *) malloc(strlen(file_path) + 1);
  char *next_sep = strchr(file_path, pathSeparator);
  while (next_sep != NULL) {
    int dir_path_len = next_sep - file_path;
    memcpy(dir_path, file_path, dir_path_len);
    dir_path[dir_path_len] = '\0';
    mkdir(dir_path, S_IRWXU|S_IRWXG|S_IROTH);
    next_sep = strchr(next_sep + 1, pathSeparator);
  }
  free(dir_path);
}

1
正如其他人所指出的,C标准库中没有跨平台支持目录的功能。
据我了解,即使是fopen()等函数,也不知道或关心你提供的路径中使用的/\作为两个主要操作系统家族中的目录分隔符。
对于单个目录创建的跨平台解决方案,请参见@dbush的answer
然后,您可以将其包装到自己的函数中,该函数将获取完整的文件/目录路径,包括所有父文件夹,并逐一创建所有必需的父文件夹(如果需要)。
为此,您需要设计一种方法,从文件路径中提取出每个连续的父目录,从最顶部/最左侧的目录开始。在C中拆分字符串时要小心,因为像strtok()这样的函数可能不安全,您最好采用不同的方法将路径转换为要创建的目录列表。

您可能还需要处理目录已经存在的情况,或者文件存在于您想放置一个目录的路径上。


0

在C标准库中,打开和写入文件的函数可以在现有目录中创建新文件,但是无法创建新目录。为了解决这个问题,建议使用头文件"sys/stat.h"中的"mkdir"函数和头文件"unistd.h"中的"chdir"函数。

例如,如果编写要在Windows 10上的Cygwin中使用的C程序,可以使用以下方法:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <error.h>
int main (void)
{
   FILE * fp;
   chdir("/cygdrive/d");
   if (mkdir("aaa", S_IRWXU|S_IRWXG|S_IROTH))
   {
      error(EXIT_FAILURE, errno, "Failed to create directory aaa");
   }
   chdir("aaa");
   if (mkdir("bbb", S_IRWXU|S_IRWXG|S_IROTH))
   {
      error(EXIT_FAILURE, errno, "Failed to create directory bbb");
   }
   chdir("bbb");
   if (mkdir("ccc", S_IRWXU|S_IRWXG|S_IROTH))
   {
      error(EXIT_FAILURE, errno, "Failed to create directory ccc");
   }
   chdir("ccc");
   fp=fopen("MyFile.txt", "w");
   if (!fp)
   {
      error(EXIT_FAILURE, errno, "Failed to open file for writing");
   }
   fprintf(fp, "Test.\n");
   fclose(fp);
   return 0;
}

这将创建目录 "D:\aaa\bbb\ccc",然后在该目录中创建名为 "MyFile.txt" 的文件,最后向该文件写入 "Test.\n"。


0

可能不如其他的那么优雅,但是:

system("mkdir aaa\\bbb\\ccc\\");
FILE * fp;
fp = fopen("aaa/bbb/ccc/myfile.txt","w");

对于 Linux,请使用 -p 选项和斜杠。

如果您正在使用 Windows,则应在 system() 函数中使用反斜杠。


@andreee 是的,但文件夹路径看起来像是从Windows系统中来的。 - C Chorche
反斜杠应该被转义,并且可以被斜杠替换。 - Basile Starynkevitch
忘了那个,谢谢。如果用户使用Windows,则终端将返回语法错误(而不是创建目录),如果使用斜杠。 - C Chorche

0

如果你的程序中可以混合一些 C++,那么 boost.filesystem 库有一个非常方便的 function 可以创建所有中间目录。

bool create_directories(const path& p);


-1
如果您正在使用fopen(),那么您应该先创建父目录。
您可以通过以下方式轻松完成:
system("mkdir -p aaa/bbb/ccc");
fopen("aaa/bbb/ccc/myfile.txt","w");

在这个程序中,不要忘记包含头文件<stdlib.h>


反斜杠应该被转义,并且可以被斜杠替换。mkdir命令可能不存在或不知道-p选项。 - Basile Starynkevitch

-3

fopen() 用于打开文本或二进制文件的输入流,而不是目录文件。如果您想要在包含不存在目录的路径中打开文件,则建议使用 /sys/stat.h 头文件的 mkdir() 方法。一旦准备好目录,您就可以使用 fopen() 打开所需的文件(如果尚不存在,则创建它)。 这是我用来在 $HOME 文件夹的一个目录中创建文件的方法:

char* home_dir= getenv("HOME"); 
/*creates the directory with specified modes*/
mkdir(strcat(home_dir, "/make-a-note/"),S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 
/*used the strcat() to generate the file-path.*/
personal_work=fopen(strcat(home_dir,"personal_work.txt"),"a+");

1
不要使用那段代码,因为 strcat() 调用是恶意的:它肯定会越界覆盖环境变量内容的缓冲区。这种未定义行为很可能会损坏某些其他环境变量,甚至更糟。 - cmaster - reinstate monica

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