Изменить текущий рабочий каталог в C ++ - PullRequest
39 голосов
/ 15 августа 2010

Как я могу изменить свой текущий рабочий каталог в C ++ независимо от платформы?

Я нашел заголовочный файл direct.h, совместимый с Windows, и unistd.h, совместимый с UNIX / POSIX.

Ответы [ 8 ]

45 голосов
/ 15 августа 2010

Функция chdir работает как в POSIX ( manpage ), так и в Windows (она называется _chdir, но существует псевдоним chdir).

Обе реализации возвращают ноль в случае успеха и -1 в случае ошибки.Как вы можете видеть на странице руководства, в варианте POSIX возможны более различимые значения errno, но это не должно иметь большого значения для большинства случаев использования.

15 голосов
/ 05 марта 2013

Для C ++ boost :: filesystem :: current_path (прототипы сеттера и геттера).

Библиотека стандартной файловой системы, основанная на Boost.Filesystem , будет добавлена ​​в стандарт..

8 голосов
/ 25 октября 2016

Этот кроссплатформенный пример кода для изменения рабочего каталога с использованием POSIX chdir и MS _chdir, как рекомендуется в этого ответа .Аналогично для определения текущего рабочего каталога используются аналогичные getcwd и _getcwd.

Эти различия в платформе скрыты за макросами cd и cwd.

Согласно документации, подпись chdir равна int chdir(const char *path), где path является абсолютным илиродственник.chdir вернет 0 в случае успеха.getcwd немного сложнее, потому что ему нужен (в одном варианте) буфер для хранения извлеченного пути, как видно из char *getcwd(char *buf, size_t size).В случае ошибки он возвращает NULL и указатель на тот же переданный буфер в случае успеха.Пример кода напрямую использует этот возвращенный указатель на символ.

Пример основан на @ MarcD, но исправляет утечку памяти.Кроме того, я стремился к краткости, отсутствию зависимостей и только базовой проверке ошибок / ошибок, а также обеспечению того, чтобы она работала на нескольких (общих) платформах.

Я тестировал ее на OSX 10.11.6, Centos7 и Win10.Для OSX и Centos я использовал g++ changedir.cpp -o changedir для сборки и работал как ./changedir <path>.

На Win10 я построил с cl.exe changedir.cpp /EHsc /nologo.

MVP решением

$ cat changeir.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 ++ changesir.c -o changeir
$ ./changedir тестирование
CWD: / Users / Phil
CWD изменен на: / Users / Phil / testing

Листинг Centos:

$ g ++ changesir.c -o changeir
$ ./changedir
Каталог не предоставлен
$ ./changedir does_not_exist
CWD: / home / phil
$ ./changedir Музыка
CWD: / home / phil
CWD измененв: / home / phil / Music
$ ./changedir /
CWD: / home / phil
CWD изменен на: /

Список Win10

cl.exe updatedir.cpp / EHsc / nologo
changeir.cpp

c: \ Users \ Phil> тест changeir.exe
CWD: c: \ Users \ Phil
CWD изменено на: c: \ Users \ Phil \ test

Примечание: OSX использует clang и Centos GNU gcc позади g++.

8 голосов
/ 15 августа 2010

chdir() делает то, что вы хотите?Работает как под POSIX, так и под Windows.

5 голосов
/ 15 августа 2010

Вы имели в виду C или C ++? Это совершенно разные языки.

В C стандарт, определяющий язык, не распространяется на каталоги. Многие платформы, поддерживающие каталоги, имеют функцию chdir, которая принимает аргумент char* или const char*, но даже там, где он существует, заголовок, в котором он объявлен, не является стандартным. Также могут быть тонкости в том, что означает аргумент (например, в Windows есть каталоги для каждого диска).

В C ++ поиск в Google приводит к chdir и _chdir и предполагает, что Boost не имеет интерфейса с chdir. Но я не буду комментировать дальше, так как я не знаю C ++.

5 голосов
/ 15 августа 2010

Вы хотите chdir(2).Если вы пытаетесь заставить вашу программу изменить рабочий каталог вашей оболочки - вы не можете.На SO уже есть множество ответов на эту проблему.

3 голосов
/ 25 октября 2016

Хороший кроссплатформенный способ изменить текущий каталог в C ++ был давно предложен @pepper_chico. Это решение использует 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
2 голосов
/ 23 октября 2016

Не могу поверить, что никто еще не требовал награду за это !!!

Вот кроссплатформенная реализация, которая получает и изменяет текущий рабочий каталог с использованием 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>

...