Как получить каталог, из которого выполняется программа?
существует ли платформа-агностический и файловая система-агностический метод для получения полного пути к каталогу, из которого выполняется программа с использованием C/C++? Не путать с текущим рабочим каталогом. (Пожалуйста, не предлагайте библиотеки, если они не являются стандартными, такими как clib или STL.)
(Если нет платформы / файловой системы-агностический метод, предложения, которые работают в Windows и Linux для конкретных файловых систем, также приветствуются.)
20 ответов:
вот код, чтобы получить полный путь к исполняющему приложению:
Windows:
int bytes = GetModuleFileName(NULL, pBuf, len); if(bytes == 0) return -1; else return bytes;Linux:
char szTmp[32]; sprintf(szTmp, "/proc/%d/exe", getpid()); int bytes = MIN(readlink(szTmp, pBuf, len), len - 1); if(bytes >= 0) pBuf[bytes] = ''; return bytes;
Если вы извлекаете текущий каталог при первом запуске программы, то у вас фактически есть каталог, из которого была запущена ваша программа. Сохраните значение в переменной и обратитесь к нему позже в своей программе. Это отличается от каталог, содержащий текущий исполняемый файл программы. Это не обязательно один и тот же каталог; если кто-то запускает программу из командной строки, то программа выполняется запустить от текущая работа командной строки каталог, даже если файл программы живет в другом месте.
getcwd является функцией POSIX и поддерживается из коробки всеми платформами, совместимыми с POSIX. Вам не нужно будет делать ничего особенного (кроме включения правильных заголовков unistd.h на Unix и direct.h на окнах).
поскольку вы создаете программу на C, она будет связана с библиотекой времени выполнения c по умолчанию, которая связана со всеми процессами в системе (специально созданные исключения избегаются), и она будет включать эта функция по умолчанию. CRT никогда не считается внешней библиотекой, потому что это обеспечивает базовый стандартный совместимый интерфейс для ОС.
в windows функция getcwd была устаревшей в пользу _getcwd. Я думаю, что вы могли бы использовать его таким образом.
#include <stdio.h> /* defines FILENAME_MAX */ #ifdef WINDOWS #include <direct.h> #define GetCurrentDir _getcwd #else #include <unistd.h> #define GetCurrentDir getcwd #endif char cCurrentPath[FILENAME_MAX]; if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))) { return errno; } cCurrentPath[sizeof(cCurrentPath) - 1] = ''; /* not really required */ printf ("The current working directory is %s", cCurrentPath);
Это форум cplusplus
на windows:
#include <string> #include <windows.h> std::string getexepath() { char result[ MAX_PATH ]; return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) ); }На Linux:
#include <string> #include <limits.h> #include <unistd.h> std::string getexepath() { char result[ PATH_MAX ]; ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX ); return std::string( result, (count > 0) ? count : 0 ); }на HP-UX:
#include <string> #include <limits.h> #define _PSTAT64 #include <sys/pstat.h> #include <sys/types.h> #include <unistd.h> std::string getexepath() { char result[ PATH_MAX ]; struct pst_status ps; if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0) return std::string(); if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0) return std::string(); return std::string( result ); }
Если вы хотите стандартный способ без библиотеки: нет. Вся концепция каталога не входит в стандарт.
Если вы согласны с тем, что некоторая (портативная) зависимость от почти стандартной lib в порядке: используйте библиотека файловой системы Boost и попросить работы функции initial_path().
IMHO это так близко, как вы можете получить, с хорошей кармой (Boost-это хорошо зарекомендовавший себя высококачественный набор библиотек)
файловая система TS в настоящее время является стандартом (и поддерживается gcc 5.3+ и clang 3.9+), так что вы можете использовать
current_path()функции из нее:std::string path = std::experimental::filesystem::current_path();в gcc (5.3+) для включения файловой системы необходимо использовать:
#include <experimental/filesystem>и свяжите свой код с
-lstdc++fsфлаг.если вы хотите использовать файловую систему с Microsoft Visual Studio, то читать это.
Я знаю, что это очень поздно в день, чтобы бросить ответ на это, но я обнаружил, что ни один из ответов были полезны для меня как мое собственное решение. Очень простой способ получить путь от вашего CWD к папке bin выглядит так:
int main(int argc, char* argv[]) { std::string argv_str(argv[0]); std::string base = argv_str.substr(0, argv_str.find_last_of("/")); }теперь вы можете просто использовать это в качестве основы для вашего относительного пути. Так например у меня есть эта структура каталогов:
main ----> test ----> src ----> binи я хочу скомпилировать мой исходный код в БИН и написать журнал для тестирования я могу просто добавить эту строку в мой код.
std::string pathToWrite = base + "/../test/test.log";Я пробовал такой подход на Linux, используя полный путь, псевдоним и т. д. и это работает просто отлично.
Примечание:
если вы находитесь на windows, вы должны использовать ' \ 'в качестве разделителя файлов не'/'. Вам также придется избежать этого, например:
std::string base = argv[0].substr(0, argv[0].find_last_of("\"));Я думаю, что это должно работать, но не тестировалось, поэтому комментарий будет оценен, если он работает или исправлен, если нет.
нет, нет стандартного способа. Я считаю, что стандарты C/C++ даже не рассматривают существование каталогов (или других организаций файловой системы).
в Windows GetModuleFileName() возвращает полный путь к исполняемому файлу процесса, когда hModule
может объединить текущий рабочий каталог с argv[0]? Я не уверен, что это будет работать в Windows, но он работает в linux.
например:
#include <stdio.h> #include <unistd.h> #include <string.h> int main(int argc, char **argv) { char the_path[256]; getcwd(the_path, 255); strcat(the_path, "/"); strcat(the_path, argv[0]); printf("%s\n", the_path); return 0; }при запуске он выдает:
jeremy@jeremy-desktop:~ / Desktop$ ./ тест
/главная/Джереми/рабочий стол/./ тест
вы не можете использовать argv[0] для этой цели, обычно он содержит полный путь к исполняемому файлу, но не nessesarily - процесс может быть создан с произвольным значением в поле.
также имейте в виду, что текущий каталог и каталог с исполняемым файлом-это две разные вещи, поэтому getcwd() вам тоже не поможет.
в Windows используйте GetModuleFileName (), в Linux read /dev/proc/procID/.. файлы.
Для Win32 GetCurrentDirectory следует сделать трюк.
для системы Windows на консоли вы можете использовать system (
dirкоманды). И консоль дает вам информацию о каталоге и т. д. Читайте о наcmd. Но для UNIX-подобных систем, я не знаю... Если эта команда запущена, прочитайте команду bash.lsне отображается в каталоге...пример:
int main() { system("dir"); system("pause"); //this wait for Enter-key-press; return 0; }
просто запоздало кучи здесь...
нет стандартного решения, потому что языки являются агностиками базовых файловых систем, поэтому, как говорили другие, концепция файловой системы на основе каталогов выходит за рамки языков c / C++.
кроме того, вы хотите не текущий рабочий каталог, а каталог, в котором работает программа, который должен учитывать, как программа попала туда, где она есть - т. е. была ли она порождена как новый процесс через вилкой и т. д. Чтобы получить каталог, в котором работает программа, как показали решения, требуется, чтобы вы получили эту информацию из структур управления процессами рассматриваемой операционной системы, которая является единственным авторитетом по этому вопросу. Таким образом, по определению, это специфическое решение для ОС.
#include <windows.h> using namespace std; // The directory path returned by native GetCurrentDirectory() no end backslash string getCurrentDirectoryOnWindows() { const unsigned long maxDir = 260; char currentDir[maxDir]; GetCurrentDirectory(maxDir, currentDir); return string(currentDir); }
команда linux bash где имя_программы сообщит путь к программе.
даже если можно было бы выдать команду which из вашей программы и направить вывод в файл tmp и программу впоследствии читает этот файл tmp, он не скажет вам, выполняется ли эта программа. Он только говорит вам, где находится программа с таким именем.
что требуется, так это получить свой идентификатор процесса и проанализировать путь к имя
в моей программе я хочу знать, если программа была выполняется из каталога bin пользователя или из другого в пути или из /usr / bin. /usr / bin будет содержать поддерживаемую версию. Мне кажется, что в Linux есть одно решение, которое является портативным.
для относительных путей, вот что я сделал. Я знаю возраст этого вопроса, я просто хочу внести более простой ответ, который работает в большинстве случаев:
скажем, у вас есть путь такой:
"path/to/file/folder"по какой-то причине, Linux-встроенные исполняемые файлы, сделанные в eclipse, отлично работают с этим. Однако, в Windows становится очень запутанной, если дается этот путь, чтобы работать с!
как указано выше есть несколько способов получить текущий путь к исполняемому файлу, но самый простой способ, который я нахожу, работает шарм в большинстве случаев-это добавление этого на передний план вашего пути:
"./path/to/file/folder"просто добавив "./ "я должен разобраться с тобой! :) Затем вы можете начать загрузку из любого каталога, который вы хотите, пока он находится с самим исполняемым файлом.
EDIT: это не будет работать, если вы попытаетесь запустить исполняемый файл из code:: blocks если это среда разработки используется, как по какой-то причине, code:: blocks не загружает вещи правильно... : D
EDIT2: некоторые новые вещи, которые я нашел, это то, что если вы укажете статический путь, подобный этому, в своем коде (предполагая пример.данные-это то, что вам нужно загрузить):
"resources/Example.data"Если вы затем запустите свое приложение из фактического каталога (или в Windows, вы сделаете ярлык и установите рабочий каталог в свой каталог приложений), то он будет работать так. Имейте это в виду при отладке проблем, связанных с отсутствием ресурсов/пути к файлам. (Особенно в IDE, которые устанавливают неправильный рабочий dir при запуске сборки exe из IDE)
на платформах POSIX вы можете использовать getcwd ().
на Windows, вы можете использовать методов _getcwd() Как использовать getcwd () была прекращена.
для стандартных библиотек, если бы Boost был достаточно стандартным для вас, я бы предложил Boost::filesystem, но они, похоже, удалили нормализацию пути из предложения. Возможно, вам придется подождать, пока TR2 становится легко доступным для полностью стандартного раствора.
повысить файловую систему
initial_path()ведет себя как, и ни то, что вы хотите сами по себе, но добавление argv[0]чтобы любой из них должен это сделать.вы можете заметить, что результат не всегда довольно-вы можете получить такие вещи, как
/foo/bar/../../baz/a.outили/foo/bar//baz/a.out, но я считаю, что это всегда приводит к допустимому пути, который называет исполняемый файл (обратите внимание, что последовательные косые черты в пути свернуты до одного).я ранее писал решение с помощью
envp(третий аргумент кmain()который работал на Linux, но не казался работоспособным на Windows, поэтому я по существу рекомендую то же самое решение, что и кто-то другой ранее, но с дополнительным объяснением того, почему это на самом деле правильно, даже если результаты не очень хороши.
Как Minok упоминалось, что нет такой функциональности, указанной в стандарте ini C или стандарте C++. Это считается чисто специфичной для ОС функцией и указывается, например, в стандарте POSIX.
Thorsten79 дал хорошее предложение, это импульс.Библиотека файловой системы. Однако это может быть неудобно, если вы не хотите иметь каких-либо зависимостей времени связи в двоичной форме для вашей программы.
хорошая альтернатива я бы рекомендуем это коллекция из 100% заголовков-только Библиотеки STLSoft C++Мэтью Уилсон (автор обязательных книг о C++). Существует портативный фасад PlatformSTL дает доступ к системному API: WinSTL для Windows и UnixSTL на Unix, поэтому это портативное решение. Все системные элементы задаются с использованием признаков и политик, поэтому это расширяемая структура. Конечно, есть библиотека файловой системы.
библиотечное решение (хотя я знаю, что это не было запрошено). Если вы случайно используете Qt:
QCoreApplication::applicationDirPath()
Comments