【问题标题】:To create all needed folders with fopen使用 fopen 创建所有需要的文件夹
【发布时间】:2014-02-09 18:29:59
【问题描述】:

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

【问题讨论】:

  • 不,fopen 永远不会创建目录。有一个question with good answers already 是关于一个扩展的mkdir(),它可以创建多个级别,这与您想要的类似。您需要在 "aaa/bbb/ccc/" 上执行该多级 mkdir,然后调用 fopen
  • 对于 windows,您可以使用这篇文章中的信息 stackoverflow.com/questions/2834737/…
  • 请记住将反斜杠加倍,一般来说就是这样。由于fopen() 根本不支持创建目录,因此无济于事,但如果存在目录,则有必要。
  • @WumpusQ.Wumbley 为什么不回答而不是发表评论?所以作者可以结束这个问题。
  • 文件夹是 GUI 人工制品。文件系统处理的是directories,它们是特定于操作系统的。标准 C11 不了解目录

标签: c fopen


【解决方案1】:

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+");

【讨论】:

  • 不要使用该代码,strcat() 调用是邪恶的:它肯定会超出保存环境变量内容的缓冲区。这种未定义的行为可能会破坏其他一些环境变量,或者更糟。
【解决方案2】:

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

bool create_directories(const path& p);

【讨论】:

    【解决方案3】:

    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”写入该文件。

    【讨论】:

      【解决方案4】:

      正如其他人所指出的,C 标准库中的目录没有跨平台支持。

      据我了解,fopen() 和朋友们甚至都不知道也不关心你给他们的路径中的/-es 或\-es 被用作两个主要的目录分隔符当今使用的操作系统系列。

      有关单个目录创建的跨平台解决方案,请参阅@dbush 的answer

      然后您可以使用您自己的函数将其包装起来,该函数将获取包括所有父文件夹在内的完整文件/目录路径,并一个接一个地创建所有必需的父文件夹(如果需要)。

      为此,您需要设计一种从文件路径中提取每个连续父目录的方法,从最顶部/最左侧的目录开始。请注意在 C 中拆分字符串,因为像 strtok() 这样的函数可能不安全——您最好使用不同的方法将路径转换为要创建的目录列表。

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

      【讨论】:

        【解决方案5】:

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

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

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

        如果您使用的是 Windows,反斜杠应该在 system() 函数中

        【讨论】:

        • @andreee 是的,但文件夹路径看起来像来自 Windows。
        • 反斜杠应该被转义,可以用斜杠代替。
        • 忘记了,谢谢。如果用户使用 Windows,如果使用斜杠,终端将返回语法错误(而不是创建目录)
        【解决方案6】:

        如果您使用的是fopen(),那么您应该先创建父目录。

        你可以这样做

        system("mkdir -p aaa/bbb/ccc");
        fopen("aaa/bbb/ccc/myfile.txt","w");
        

        不要忘记在这个程序中包含头文件&lt;stdlib.h&gt;

        【讨论】:

        • 反斜杠应该被转义,可以用斜杠代替。 mkdir 命令可能不存在或不知道 -p
        【解决方案7】:

        这是另一种用纯 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);
        }
        

        【讨论】:

          猜你喜欢
          • 2015-10-26
          • 1970-01-01
          • 1970-01-01
          • 2016-02-26
          • 2011-02-19
          • 2016-04-10
          • 2011-07-18
          • 1970-01-01
          相关资源
          最近更新 更多