【问题标题】:Change the current working directory in C++更改 C++ 中的当前工作目录
【发布时间】:2011-03-29 22:45:54
【问题描述】:

如何以与平台无关的方式在 C++ 中更改我当前的工作目录?

我找到了与 Windows 兼容的 direct.h 头文件和与 UNIX/POSIX 兼容的 unistd.h

【问题讨论】:

  • @noɥʇʎPʎzɐɹC 所以标准委员会已经建立了一个标准的方法来改变工作目录,大约 C++17,通过filesystempepper_chico's answer 已经表明了这一点。 filesystem 目前在 g++5.3 和 Visual Studio 2015 中作为可选包含提供。如果这是您工作的环境,我可以使用#ifdef 给您写一个答案,让filesystem 跨平台访问?
  • @JonathanMee 如果足够好,我可能会做多次赏金

标签: c++ header portability working-directory


【解决方案1】:

现在,C++17 可以使用std::filesystem::current_path

#include <filesystem>
int main() {
    auto path = std::filesystem::current_path(); //getting path
    std::filesystem::current_path(path); //setting path
}

【讨论】:

  • 这只会改变当前进程的路径。操作shell的当前路径没有改变。
【解决方案2】:

此跨平台示例代码使用 POSIX chdir 和 MS _chdir 更改工作目录,如 this answer 中推荐的那样。同样,为了确定当前工作目录,使用类似的getcwd_getcwd

这些平台差异隐藏在宏 cdcwd 后面。

根据文档,chdir 的签名是int chdir(const char *path),其中path 是绝对的或相对的。 chdir 将在成功时返回 0。 getcwd 稍微复杂一些,因为它需要(在一个变体中)一个缓冲区来存储获取的路径,如 char *getcwd(char *buf, size_t size) 所示。它在失败时返回 NULL,在成功时返回指向同一个传递缓冲区的指针。代码示例直接使用了这个返回的 char 指针。

该示例基于@MarcD,但更正了内存泄漏。此外,我力求简洁,没有依赖关系,只进行基本的故障/错误检查,并确保它可以在多个(通用)平台上运行。

我在 OSX 10.11.6、Centos7 和 Win10 上对其进行了测试。对于 OSX 和 Centos,我使用 g++ changedir.cpp -o changedir 构建并以 ./changedir &lt;path&gt; 运行。

在 Win10 上,我使用 cl.exe changedir.cpp /EHsc /nologo 构建。

MVP 解决方案

$ cat changedir.cpp

#ifdef _WIN32
#include <direct.h>
// MSDN recommends against using getcwd & chdir names
#define cwd _getcwd
#define cd _chdir
#else
#include "unistd.h"
#define cwd getcwd
#define cd chdir
#endif

#include <iostream>

char buf[4096]; // never know how much is needed

int main(int argc , char** argv) {

  if (argc > 1) {
    std::cout  << "CWD: " << cwd(buf, sizeof buf) << std::endl;

    // Change working directory and test for success
    if (0 == cd(argv[1])) {
      std::cout << "CWD changed to: " << cwd(buf, sizeof buf) << std::endl;
    }
  } else {
    std::cout << "No directory provided" << std::endl;
  }

  return 0;
}

OSX 上市:

$ g++ changedir.c -o changedir
$ ./changedir 测试
CWD:/用户/Phil
CWD 更改为:/Users/Phil/testing

Centos 列表:

$ g++ changedir.c -o changedir
$ ./changedir
未提供目录
$ ./changedir does_not_exist
CWD: /home/phil
$ ./changedir 音乐
CWD: /home/phil
CWD 更改为:/home/phil/Music
$ ./changedir /
CWD: /home/phil
CWD 更改为:/

Win10上市

cl.exe 更改了ir.cpp /EHsc /nologo
改变ir.cpp

c:\Users\Phil> changedir.exe 测试
CWD: c:\Users\Phil
CWD 改为:c:\Users\Phil\test

注意:OSX 在g++ 后面使用clang 和Centos gnu gcc

【讨论】:

  • 哦,您为此付出了很多努力。你在我的名单上领先!
  • 比库更短,而且干净整洁。提供一个清晰的说明如何设置和获取cwd,现在有点模糊。
  • @noɥʇʎPʎzɐɹC 如果您不清楚更新,请告诉我。
  • 在 Windows 上对我不起作用。条件 argc > 1 的目的是什么?不带参数的应用允许有工作目录。
  • @DietrichBaumgarten - 你看到错误了吗? argc 条件是为了保护演示程序中对 argv 的索引。
【解决方案3】:

@pepper_chico 很久以前就提出了在 C++ 中更改当前目录的好方法。此解决方案使用boost::filesystem::current_path()

要获取当前工作目录,请使用:

namespace fs = boost::filesystem;
fs::path cur_working_dir(fs::current_path());

设置当前工作目录使用:

namespace fs = boost::filesystem;
fs::current_path(fs::system_complete( fs::path( "new_working_directory_path" ) ));    

下面是自包含的辅助函数:

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include <string>

namespace fs = boost::filesystem;    

fs::path get_cwd_pth()
{
  return fs::current_path();
}   

std::string get_cwd()
{ 
  return get_cwd_pth().c_str();
} 

void set_cwd(const fs::path& new_wd)
{
  fs::current_path(fs::system_complete( new_wd));
}   

void set_cwd(const std::string& new_wd)
{
  set_cwd( fs::path( new_wd));
}

这是我关于如何设置/获取当前工作目录的完整代码示例:

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include <iostream>

namespace fs = boost::filesystem;

int main( int argc, char* argv[] )
{
  fs::path full_path;
  if ( argc > 1 )
  {
    full_path = fs::system_complete( fs::path( argv[1] ) );
  }  
  else
  {
    std::cout << "Usage:   tcd [path]" << std::endl;
  }

  if ( !fs::exists( full_path ) )
  {
    std::cout << "Not found: " << full_path.c_str() << std::endl;
    return 1;
  }

  if ( !fs::is_directory( full_path ))
  {
    std::cout << "Provided path is not a directory: " << full_path.c_str() << std::endl;
    return 1;
  }

  std::cout << "Old current working directory: " << boost::filesystem::current_path().c_str() << std::endl;

  fs::current_path(full_path);

  std::cout << "New current working directory: " << boost::filesystem::current_path().c_str() << std::endl;
  return 0;
}

如果您的系统上安装了boost,您可以使用以下命令编译此示例:

g++ -o tcd app.cpp -lboost_filesystem -lboost_system

【讨论】:

  • 为更改和查看当前工作目录提供一个干净且隔离的单行。
  • 还有一个功能供需要的人使用
  • @noɥʇʎPʎzɐɹC 添加了几个辅助函数以同时使用std::stringboost::filesystem::path
  • @noɥʇʎPʎzɐɹC 没问题,已更新名称以符合 boost 命名和典型的 C++ 代码样式。
  • @noɥʇʎPʎzɐɹC Thnx,已接受更改。我还在那里缩短了一个变量名。
【解决方案4】:

chdir 函数适用于 POSIX (manpage) 和 Windows(在此称为 _chdir,但存在别名 chdir)。

两种实现都在成功时返回零,在错误时返回 -1。正如您在手册页中看到的那样,在 POSIX 变体中可能会出现更显着的 errno 值,但这对于大多数用例来说并不会真正产生影响。

【讨论】:

  • 我在问,因为 Visual Studio 希望我使用 direct.h,但是当我尝试在 Linux 中构建相同的代码时,它崩溃了,说我需要使用 unistd.h
  • @sparkFinder,在处理 chdir() 等非标准函数时,通常需要在不同平台上包含不同的标头。 IIRC,GCC 将在面向 Windows 时定义 _WIN32,因此您可以将其与 #include 一起使用来选择标题。
  • @sparkFinder:您可以使用 #ifdef _MSC_VER 检查 Visual Studio,然后包含 direct.h 标头。如果未定义,请使用 unistd.h。这应该足够了,因为 Windows 上的另一个主要编程环境 MinGW 具有 unistd 标头。
  • chdir 在 windows 上已弃用。
  • @dbush _chdir != chdir _chdir 不是跨平台的,而 chdir 已弃用。
【解决方案5】:

不敢相信还没有人在这颗上获得赏金!!!

这是一个使用 C++ 获取和更改当前工作目录的跨平台实现。只需要一点宏魔法,读取 argv[0] 的值,并定义一些小函数。

这里是将目录更改为当前正在运行的可执行文件位置的代码。它可以很容易地适应将当前工作目录更改为您想要的任何目录。

代码:

  #ifdef _WIN32
     #include "direct.h"
     #define PATH_SEP '\\'
     #define GETCWD _getcwd
     #define CHDIR _chdir
  #else
     #include "unistd.h"
     #define PATH_SEP '/'
     #define GETCWD getcwd
     #define CHDIR chdir
  #endif

  #include <cstring>
  #include <string>
  #include <iostream>
  using std::cout;
  using std::endl;
  using std::string;

  string GetExecutableDirectory(const char* argv0) {
     string path = argv0;
     int path_directory_index = path.find_last_of(PATH_SEP);
     return path.substr(0 , path_directory_index + 1);
  }

  bool ChangeDirectory(const char* dir) {return CHDIR(dir) == 0;}

  string GetCurrentWorkingDirectory() {
     const int BUFSIZE = 4096;
     char buf[BUFSIZE];
     memset(buf , 0 , BUFSIZE);
     GETCWD(buf , BUFSIZE - 1);
     return buf;
  }

  int main(int argc , char** argv) {

     cout << endl << "Current working directory was : " << GetCurrentWorkingDirectory() << endl;
     cout << "Changing directory..." << endl;

     string exedir = GetExecutableDirectory(argv[0]);
     ChangeDirectory(exedir.c_str());

     cout << "Current working directory is now : " << GetCurrentWorkingDirectory() << endl;

     return 0;
  }

输出:

c:\Windows>c:\ctwoplus\progcode\test\CWD\cwd.exe

当前工作目录是:c:\Windows 更改目录... 当前工作目录现在是:c:\ctwoplus\progcode\test\CWD

c:\Windows>

【讨论】:

  • 很好的例子。但是清理并缩短您的代码,它将是您的。
  • @noɥʇʎPʎzɐɹC 怎么样?我把它缩短了一点,把它清理干净了。不能再缩短了。
  • 清理了一下。我将对其进行测试并为 posix 运行一个示例,然后您将获得赏金。 :)
  • 做了一个迷你代码审查:gist.github.com/CrazyPython/152805717b1c01649f0efed3415001e0(它不适用于 unix)
  • 它按预期工作。你想让它做什么?但不会转义它会转换为字符串
【解决方案6】:

chdir() 做你想做的事吗?它适用于 POSIX 和 Windows。

【讨论】:

    【解决方案7】:

    对于 C++,boost::filesystem::current_path(setter 和 getter 原型)。

    一个基于Boost.Filesystem will be added to the standard的文件系统库。

    【讨论】:

      【解决方案8】:

      您是指 C 还是 C++?它们是完全不同的语言。

      在 C 中,定义语言的标准不包括目录。许多支持目录的平台都有一个chdir 函数,它接受char*const char* 参数,但即使它存在,声明它的标头也不是标准的。参数的含义也可能有些微妙之处(例如,Windows 具有每个驱动器的目录)。

      在 C++ 中,谷歌搜索会导致 chdir_chdir,并表明 Boost 没有到 chdir 的接口。但我不会进一步评论,因为我不懂 C++。

      【讨论】:

      • 在 boost::filesystem 中,我上次使用时没有“chdir”。
      • @rubber:确实,查看boost.org/doc/libs/1_34_1/boost/filesystem/operations.hpp 表明存在getcwd 等价物,但没有chdir 等价物。
      • 如果 C 和 C++ 是您所知道的仅有的两种语言,我可以看到人们会如何认为它们是完全不同的语言。或者如果你只知道 C 语言
      • @Michael C 和 C++ 有许多共同点:它们是不安全的命令式语言。尽管如此,它们是完全不同的语言,比 C# 和 Java 更远。确实,C 和 C++ 有一个相当大的公共子集,但这个公共子集几乎从来都不是好的 C 或好的 C++。如果你认为 C 是 C++ 的一个子集,那么你要么是一个糟糕的 C 程序员,要么是一个糟糕的 C++ 程序员,或者两者兼而有之。
      【解决方案9】:

      你想要chdir(2)。如果你试图让你的程序改变你的 shell 的工作目录——你不能。已经有很多关于 SO 的答案已经解决了这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-24
        • 2014-01-14
        • 2019-05-20
        • 2014-12-02
        • 2015-02-22
        相关资源
        最近更新 更多