有没有一种与平台无关、与文件系统无关的方法来获取使用C/C++运行的程序所在目录的完整路径?不要与当前工作目录混淆。(请不要推荐库,除非是标准库,如clib或STL)。
(如果没有与平台/文件系统相关的方法,也欢迎提供在Windows和Linux中对特定文件系统有效的建议)。)
以下是获取执行应用程序完整路径的代码。
int bytes = GetModuleFileName(NULL, pBuf, len);
if(bytes == 0)
return -1;
else
return bytes;
}
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] = '\0';
return bytes;
如果你在程序第一次启动时获取了当前的目录,那么你实际上就拥有了程序启动时的目录。 将该值存储在一个变量中,并在以后的程序中引用它。 这与【存放当前可执行程序文件的目录】(https://stackoverflow.com/q/933850/33732)不同。 它不一定是同一个目录。 如果有人从命令提示符中运行程序,那么程序就是从*命令提示符'的当前工作目录中运行的,即使程序文件位于其他地方。
getcwd 是一个 POSIX 函数,所有兼容 POSIX 的平台都支持它。 你不需要做任何特别的事情(除了在Unix上加入正确的标题unistd.h,在windows上加入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] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
这是来自[cplusplus论坛][1]的。
在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 [现在是一个标准][1] (并且被 gcc 5.3+ 和 clang 3.9+ 支持),所以你可以使用它的 [current_path()
][2] 函数。
std::string path = std::experimental::filesystem::current_path();
在gcc(5.3+)中,你需要使用Filesystem。
#include <experimental/filesystem>
并用-lstdc++fs
标志连接你的代码。
如果你想在Microsoft Visual Studio中使用Filesystem,那么阅读这个。
[1]: http://www.iso.org/iso/catalogue_detail.htm?csnumber=63483 [2]: http://en.cppreference.com/w/cpp/experimental/fs/current_path
我知道现在回答这个问题已经很晚了,但是我发现所有的答案对我来说都不如我自己的解决方案有用。 一个非常简单的方法是这样获取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
main
----> test
----> src
----> bin
我想把我的源代码编译成bin,然后写一个日志来测试,我可以在我的代码中加入这行。
std::string pathToWrite = base + "/../test/test.log";
我曾在Linux上尝试过这种使用全路径、别名等方法。 结果效果还不错。
注意。
如果你是在windows上,你应该使用'\' 作为文件分隔符,而不是'/'。 例如,你也必须使用转义符。
std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));
我认为这应该工作,但没有'测试,所以评论将被感激,如果它的工作或修复,如果没有。
也许用 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;
}
}
#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$ ./test; jeremy@jeremy-desktop:~/Desktop$ ./test。
/home/jeremy/Desktop/./test
在Windows上,最简单的方法是使用stdlib.h
中的_get_pgmptr
函数来获取一个指向一个字符串的指针,这个字符串代表可执行文件的绝对路径,包括可执行文件的名称。
char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
我只是想在这里迟迟地说一句,...
没有标准的解决方案,因为这些语言对底层的文件系统是不可知的,所以正如其他人所说,基于目录的文件系统的概念不在c / c++语言的范围之内。
除此之外,你需要的不是当前的工作目录,而是程序运行的目录,这必须考虑到程序是如何到达现在的位置的--即它是通过fork作为一个新的进程产生的,等等。 要获得程序运行的目录,正如解决方案所证明的那样,需要从操作系统的进程控制结构中获得这些信息,而操作系统是这个问题的唯一权威。 因此,从定义上看,它是一个针对操作系统的解决方案。
#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 progname会报告一个程序的路径。
即使你可以在你的程序中发出which命令,并将输出直接指向一个tmp文件和程序 随后读取该tmp文件,它不会告诉你该程序是否正在执行。 它只告诉你一个有这个名字的程序在哪里。
需要做的是获取你的进程ID号,并解析出这个名字的路径。
在我的程序中,我想知道程序是否是 从用户的bin目录或路径中的其他目录中执行。 或从/usr/bin。 /usr/bin将包含支持的版本。 我的感觉是,在Linux中,有一个解决方案是可移植的。
对于相对路径,我是这样做的'。 我知道这个问题的年代久远,我只是想贡献一个更简单的答案,在大多数情况下都能用。
假设你有一条这样的路径
"path/to/file/folder"
出于某些原因,用eclipse制作的Linux可执行文件可以正常工作。 然而,如果给windows一个这样的路径,它就会变得非常困惑。
如上所述,有几种方法可以获得当前可执行文件的路径,但我发现最简单的方法就是在路径的前面加上这个。
"./path/to/file/folder"
只要加上"./" 就可以了! :) 然后你就可以从任何你想要的目录开始加载了,只要是用可执行文件本身就可以了。
EDIT: 如果你尝试从code::block启动可执行文件,如果使用的是开发环境的话,这个方法是行不通的,因为出于某种原因,code::block并不能正确加载东西...... :D
EDIT2: 我发现了一些新的东西,如果你在代码中指定了一个静态路径,比如这个 (假设 Example.data 是你需要加载的东西):
"resources/Example.data"
如果你然后从实际的目录中启动你的应用程序(或者在Windows中,你做一个快捷方式,并将工作dir设置为你的应用程序dir),那么它就会像这样工作。 在调试与资源/文件路径丢失有关的问题时,请记住这一点。 (尤其是在IDE中,当从IDE启动编译exe时,设置了错误的工作dir)
Boost Filesystem的initial_path()
和POSIX的getcwd()
一样,两者都不能单独完成你想要的事情,但是在其中任何一个后面添加argv[0]
就可以了。
你可能会注意到,结果并不总是很好--你可能会得到/foo/bar/.../.../baz/a.out
或/foo/bar//baz/a.out
这样的结果,但我相信它总是会得到一个有效的路径,并将其命名为可执行文件(注意路径中的连续斜线会被折叠为一个)。
我以前写过一个解决方案,使用envp
(main()
的第三个参数,在Linux上可以工作,但在Windows上似乎行不通,所以我基本上推荐和别人以前做的一样的解决方案,但要额外解释为什么它实际上是正确的,即使结果不好看。
正如Minok所提到的,在C标准或C++标准中并没有规定这种功能。 这被认为是纯粹的操作系统专用功能,例如在POSIX标准中就有规定。
Thorsten79给出了一个很好的建议,那就是Boost.Filesystem库。 然而,如果你不想让你的程序有任何二进制形式的链接时间依赖,那么它可能会很不方便。
我推荐的一个很好的替代方案是100%只用头的STLSoft C++ Libraries[Matthew Wilson][2](C++必读书籍的作者)的集合。 有可移植的门面PlatformSTL提供了对系统特定API的访问。 Windows的WinSTL和Unix的UnixSTL,所以它是可移植的解决方案。 所有系统特定的元素都是通过使用特征和策略来指定的,所以它是一个可扩展的框架。 当然,还提供了文件系统库。
1:
[2]: http://en.wikipedia.org/wiki/Matthew_Wilson_%28author%29
从C++11开始使用实验性文件系统,C++14-C++17也可以使用官方文件系统。
application.h.程序。
#pragma once
//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>
namespace std {
namespace filesystem = experimental::filesystem;
}
#endif
std::filesystem::path getexepath();
application.cpp:
#include "application.h"
#ifdef _WIN32
#include <windows.h> //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h> //readlink
#endif
std::filesystem::path getexepath()
{
#ifdef _WIN32
wchar_t path[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, path, MAX_PATH);
return path;
#else
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#endif
}