如何获取程序正在运行的目录?

是否有一种平台不可知和文件系统不可知的方法来获取程序运行的目录的完整路径?不要与当前工作目录混淆。(请不要推荐库,除非它们是像clib或STL这样的标准库。)

(如果没有平台/文件系统不可知的方法,也欢迎在Windows和Linux中针对特定文件系统工作的建议。)

551560 次浏览

对于Win32, GetCurrentDirectory应该做到这一点。

不,没有标准的方法。我相信C/ c++标准甚至没有考虑目录(或其他文件系统组织)的存在。

在Windows上,当hModule参数被设置为时,GetModuleFileName ()将返回当前进程可执行文件的完整路径。Linux我帮不上忙。

此外,您还应该明确您想要的是当前目录还是程序映像/可执行文件所在的目录。就目前情况来看,你的问题在这一点上有点模棱两可。

如果你想要一种没有库的标准方式:不。标准中没有包含目录的整个概念。

如果你同意对一个接近标准库的某些(可移植的)依赖是可以的:使用Boost的文件系统库并请求initial_path (). dll。

恕我直言,这是你能得到的最接近的结果,并且有良好的因果报应(Boost是一套完善的高质量库)

在POSIX平台上,你可以使用getcwd ()

在Windows上,你可以使用_getcwd (),因为使用getcwd ()已被弃用。

对于标准库,如果Boost对您来说足够标准,那么我会建议Boost::filesystem,但是他们似乎已经从建议中删除了路径规范化。你可能要等到TR2变得唾手可得才能得到一个完全标准的解决方案。

也许连接当前工作目录与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;
}

运行时输出:

< p > jeremy@jeremy-desktop: ~ /桌面。美元/测试< br > /home/jeremy/Desktop/./test < / p >

你不能为此目的使用argv[0],通常它包含可执行文件的完整路径,但也不是必须的——进程可以在字段中使用任意值创建。

还要注意,当前目录和可执行文件所在的目录是两个不同的东西,所以getcwd()也帮不了你。

在Windows上使用GetModuleFileName(),在Linux上读取/dev/proc/ __abc0 ..文件。

Boost Filesystem的initial_path()的行为类似POSIX的getcwd(),它们本身都不能实现你想要的效果,但是将argv[0]附加到它们中的任何一个都可以实现。

你可能会注意到结果并不总是很漂亮——你可能会得到/foo/bar/../../baz/a.out/foo/bar//baz/a.out这样的东西,但我相信它总是会产生一个有效的路径,该路径命名了可执行文件(注意路径中连续的斜杠被折叠为一个)。

我之前用envp (main()的第三个参数,在Linux上有效,但在Windows上似乎行不通,所以我基本上是在推荐和其他人之前做的相同的解决方案,但附加了为什么它实际上是正确的,即使结果不太漂亮。

如果在程序第一次启动时获取当前目录,那么实际上就拥有了启动程序的目录。将值存储在一个变量中,稍后在程序中引用它。这与保存当前可执行程序文件的目录不同。它不一定是同一个目录;如果有人从命令提示符运行程序,则该程序位于命令提示符的当前工作目录,即使该程序文件位于其他地方。

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);

下面是获取执行应用程序的完整路径的代码:

变量声明:

char pBuf[256];
size_t len = sizeof(pBuf);

窗口:

int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;

Linux:

int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;

只是迟来的堆砌在这里,…

没有标准的解决方案,因为这些语言不知道底层文件系统,所以正如其他人所说,基于目录的文件系统的概念超出了c / c++语言的范围。

最重要的是,你想要的不是当前的工作目录,而是程序运行的目录,这必须考虑到程序是如何到达它所在的位置的——例如,它是否是通过fork生成的新进程,等等。如解决方案所示,要获取程序运行的目录,需要从相关操作系统的进程控制结构获取信息,这是在这个问题上的唯一权威。因此,根据定义,这是一个特定于操作系统的解决方案。

正如Minok所提到的,在C标准或c++标准中没有指定这样的功能。例如,这被认为纯粹是特定于操作系统的特性,并且在POSIX标准中指定。

Thorsten79给出了很好的建议,它是Boost。文件系统库。然而,如果你不想让你的程序有任何二进制形式的链接时间依赖关系,这可能是不方便的。

我推荐的一个很好的替代方法是100%只包含header的STLSoft c++库 马修威尔逊(关于c++的必读书籍的作者)。PlatformSTL提供了对系统特定API的访问:Windows上的WinSTL和Unix上的UnixSTL,因此它是可移植的解决方案。所有特定于系统的元素都是使用特征和策略指定的,因此它是可扩展的框架。当然,还提供了文件系统库。

在Windows上,最简单的方法是使用stdlib.h中的_get_pgmptr函数来获取指向一个字符串的指针,该字符串表示可执行文件的绝对路径,包括可执行文件的名称。

char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe

对于控制台的Windows系统,可以使用system(dir)命令。控制台提供目录等信息。在cmd上阅读有关dir命令的信息。但是对于类unix系统,我不知道…如果执行了该命令,请读取bash命令。ls不显示目录…

例子:

int main()
{
system("dir");
system("pause"); //this wait for Enter-key-press;
return 0;
}

这是来自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 );
}
#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);
}

对于相对路径,我是这样做的。我知道这个问题的年代久远,我只是想提供一个在大多数情况下都适用的更简单的答案:

假设你有一个这样的路径:

"path/to/file/folder"

出于某种原因,在eclipse中构建的linux可执行文件可以很好地使用它。然而,如果给窗口一个这样的路径来工作,它会变得非常混乱!

如上所述,有几种方法可以获得可执行文件的当前路径,但我发现在大多数情况下最简单的方法是将其附加到路径的FRONT:

"./path/to/file/folder"

只是补充”。/“应该让你整理好!”:)然后你可以从任何你想要的目录开始加载,只要它是可执行文件本身。

编辑:如果您试图从code::blocks启动可执行文件,这将不起作用,如果这是正在使用的开发环境,由于某些原因,code::blocks不能正确加载东西…: D

EDIT2:我发现的一些新情况是,如果您在代码中指定一个像这样的静态路径(假设示例。数据是你需要加载的东西):

"resources/Example.data"
如果你从实际目录中启动你的应用程序(或者在Windows中,你做了一个快捷方式,并将工作目录设置为你的应用程序目录),那么它将像这样工作。 在调试与缺少资源/文件路径相关的问题时,请记住这一点。(特别是在IDE中,当从IDE启动构建exe时设置了错误的工作目录)

我知道现在回答这个问题已经很晚了,但我发现没有一个答案像我自己的解决方案那样对我有用。一个非常简单的方法来获取路径从你的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

我想把我的源代码编译到bin并写一个日志来测试,我可以把这一行添加到我的代码中。

std::string pathToWrite = base + "/../test/test.log";

我在Linux上尝试过这种方法,使用全路径,别名等,它工作得很好。

注意:

如果你是在windows中,你应该使用“\”作为文件分隔符,而不是“/”。你也需要转义这个,例如:

std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));

我认为这应该工作,但还没有测试,所以评论将是感激如果它工作或修复如果不是。

文件系统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标志链接。

如果你想在microsoftvisualstudio中使用Filesystem,则读到这

linux bash命令 哪个progname将报告程序的路径。

即使有人可以在程序中发出which命令,并将输出直接输出到tmp文件和程序 随后读取TMP文件,它不会告诉您该程序是否是正在执行的程序。它只告诉你具有该名称的程序位于何处

所需要的是获取进程id号,并解析出该名称的路径

在我的程序中,我想知道程序是否 从用户的bin目录或路径中的其他目录执行 或者从/usr/bin。/usr/bin将包含受支持的版本。 我的感觉是在Linux中有一个可移植的解决方案

一个库解决方案(尽管我知道这不是被要求的)。 如果你恰好使用Qt: QCoreApplication::applicationDirPath() < / p >

像这样在stdlib.h中使用realpath():

char *working_dir_path = realpath(".", NULL);

从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
}

只是我的两美分,但下面的代码在c++ 17中不能移植吗?

#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;


int main(int argc, char* argv[])
{
std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}

至少在Linux上对我有用。

根据前面的想法,我现在有:

std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");

与实现:

fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
static auto exe_parent_path = fs::path(exe_path).parent_path();
return exe_parent_path / filename;
}

main()中的初始化技巧:

(void) prepend_exe_path("", argv[0]);

感谢@Sam Redway的argv[0]想法。当然,我知道当OP提出这个问题时,c++ 17还没有出现很多年。

当前.exe的路径


#include <Windows.h>


std::wstring getexepathW()
{
wchar_t result[MAX_PATH];
return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}


std::wcout << getexepathW() << std::endl;


//  -------- OR --------


std::string getexepathA()
{
char result[MAX_PATH];
return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}


std::cout << getexepathA() << std::endl;


下面的操作在macOS 10.15.7上运行得很好

brew install boost

main.cpp

#include <iostream>
#include <boost/filesystem.hpp>


int main(int argc, char* argv[]){
boost::filesystem::path p{argv[0]};
p = absolute(p).parent_path();
std::cout << p << std::endl;
return 0;
}

编译

g++ -Wall -std=c++11 -l boost_filesystem main.cpp