Изменение текущего рабочего каталога в C++
Как я могу изменить свой текущий рабочий каталог на C++ агностическим способом платформы?
нашел direct.h
файл заголовка, который совместим с Windows, и unistd.h
, который совместим с UNIX / POSIX.
8 ответов
на chdir
функция работает на обоих POSIX (manpage) и Windows (называется _chdir
там только псевдоним ).
обе реализации возвращают ноль при успехе и -1 при ошибке. Как вы можете видеть в manpage, более различающиеся значения errno возможны в варианте POSIX, но это не должно иметь значения для большинства случаев использования.
Для C++, boost:: filesystem:: current_path (прототипы сеттера и геттера).
библиотека файловой системы на основе Boost.Файловая система будет добавлен в стандарт.
этот кросс-платформенный пример кода для изменения рабочего каталога с помощью POSIX chdir
и MS _chdir
как рекомендуют в ответ. Аналогично для определения текущего рабочего каталога, аналогичный getcwd
и _getcwd
есть.
эти различия платформы скрыты за макросами cd
и cwd
.
согласно документации, chdir
'подпись S составляет int chdir(const char *path)
здесь path
is абсолютный или относительный. 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 <path>
.
на 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
Каталог не предоставляется
$ ./does_not_exist changedir
CWD:/главная / Фил
$ ./ changedir Music
CWD:/главная / Фил
CWD изменено на: / home/phil / Music
$ ./changedir /
CWD:/главная / Фил
CWD изменен на: /
Win10 Листинг
cl.exe changedir.cpp /EHsc / nologo
changedir.cppc:\Users\Phil > changedir.ехе тест
CWD: c:\Users\Phil
CWD изменен на: c:\Users\Phil\test
Примечание: OSX использует clang
и Centos gnu gcc
за g++
.
вы хотите chdir(2)
. Если вы пытаетесь заставить свою программу изменить рабочий каталог вашей оболочки - вы не можете. Есть много ответов на SO, уже решающих эту проблему.
вы имели в виду C или C++? Это совершенно разные языки.
в C стандарт, определяющий язык, не охватывает каталоги. Многие платформы, поддерживающие каталоги, имеют chdir
функция, которая принимает char*
или const char*
аргумент, но даже там, где он существует, заголовок, где он объявлен, не является стандартным. Также могут быть тонкости относительно того, что означает аргумент (например, Windows имеет каталоги на диске).
в C++ поиск в интернете приводит к chdir
и _chdir
, и предполагает, что Boost не имеет интерфейса для chdir. Но я не буду комментировать дальше, так как я не знаю C++.
Не могу поверить, что никто еще не претендовал на награду за это!!!
вот кросс-платформенная реализация, которая получает и изменяет текущий рабочий каталог с помощью 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>
хороший кросс-платформенный способ изменить текущий каталог на 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