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

时间:2008-09-27 07:18:29

标签: c++ c working-directory

是否存在与平台无关且与文件系统无关的方法来获取使用C / C ++运行程序的目录的完整路径?不要与当前的工作目录混淆。 (请不要建议使用库,除非它们是clib或STL等标准库。)

(如果没有平台/文件系统无关的方法,也欢迎在Windows和Linux中使用特定文件系统的建议。)

24 个答案:

答案 0 :(得分:168)

这是获取正在执行的应用程序的完整路径的代码:

视窗:

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;

答案 1 :(得分:162)

如果在程序首次启动时获取当前目录,则可以有效地获取程序启动目录。将值存储在变量中,稍后在程序中引用它。这与the directory that holds the current executable program file不同。它不一定是同一个目录;如果有人从命令提示符运行程序,那么程序正在命令提示符的当前工作目录运行,即使程序文件位于其他地方。

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

答案 2 :(得分:36)

这来自cplusplus forum

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

答案 3 :(得分:28)

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

如果您同意对近标准库的某些(可移植)依赖是可以的:使用Boost's filesystem library并请求initial_path()

恕我直言,尽可能接近,有良好的业力(Boost是一套完善的高质量图书馆)

答案 4 :(得分:17)

Filesystem TS is now a standard(并受gcc 5.3+和clang 3.9+支持),因此您可以使用current_path()函数:

std::string path = std::experimental::filesystem::current_path();

在gcc(5.3+)中包含你需要使用的Filesystem:

#include <experimental/filesystem>

并将您的代码与-lstdc++fs标记相关联。

如果要将文件系统与Microsoft Visual Studio一起使用,则read this

答案 5 :(得分:17)

我知道现在很晚才回答这个问题,但我发现没有一个答案对我来说和我自己的解决方案一样有用。获取从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上,你应该使用&#39; \&#39;作为文件分隔符不是&#39; /&#39;。你也必须逃避这个例子:

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

我认为这应该有效,但尚未经过测试,因此如果有效,可以表示赞赏,如果没有,则表示感谢。

答案 6 :(得分:9)

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

在Windows上,当 hModule 参数设置为 NULL GetModuleFileName()将返回当前进程的可执行文件的完整路径>。我无法帮助Linux。

此外,您应该澄清您是否需要当前目录或程序映像/可执行文件所在的目录。就目前而言,你的问题在这一点上有点含糊不清。

答案 7 :(得分:7)

也许将当前工作目录与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 $ ./test
  /家庭/杰里米/桌面/./测试

答案 8 :(得分:6)

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

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

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

答案 9 :(得分:6)

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

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

答案 10 :(得分:5)

对于Win32 GetCurrentDirectory应该这样做。

答案 11 :(得分:3)

对于Windows系统的控制台,您可以使用system(dir)命令。并且控制台为您提供有关目录等的信息。请阅读dir处的cmd命令。但对于类Unix系统,我不知道......如果运行此命令,请阅读bash命令。 ls不显示目录...

示例:

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

答案 12 :(得分:3)

刚好迟到了,......

没有标准的解决方案,因为语言与底层文件系统无关,正如其他人所说的那样,基于目录的文件系统的概念超出了c / c ++语言的范围。

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

答案 13 :(得分:2)

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

答案 14 :(得分:1)

对于相对路径,这就是我所做的。我知道这个问题的年龄,我只想提供一个在大多数情况下有效的简单答案:

假设您有这样的路径:

"path/to/file/folder"

出于某种原因,在Eclipse中制作的Linux构建的可执行文件可以正常工作。但是,如果给出像这样的路径,windows会变得非常混乱!

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

"./path/to/file/folder"

只需添加“./”即可让您排序! :)然后你就可以从你想要的任何目录开始加载,只要它与可执行文件本身一起。

编辑:如果您尝试从代码:: blocks启动可执行文件,如果这是正在使用的开发环境,这将无效,因为某些原因,code :: blocks不能正确加载...:D

EDIT2:我发现的一些新事物是,如果你在代码中指定一个像这样的静态路径(假设你需要加载Example.data):

"resources/Example.data"

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

答案 15 :(得分:1)

linux bash命令 哪个progname 会报告一个程序路径。

即使可以从程序中发出which命令并将输出定向到tmp文件和程序 随后读取该tmp文件,它不会告诉您该程序是否正在执行。它只会告诉您具有该名称的程序所在的位置。

所需要的是获取您的进程ID号,并解析名称的路径

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

答案 16 :(得分:1)

只需两美分,但以下代码在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已经存在了很多年。

答案 17 :(得分:1)

当前 .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;

答案 18 :(得分:0)

如上所述 Minok ,在C标准或C ++标准中没有指定此类功能。这被认为是纯OS特有的功能,例如在POSIX标准中指定。

Thorsten79 给出了很好的建议,它是Boost.Filesystem库。但是,如果您不希望以二进制形式为程序提供任何链接时依赖性,则可能不方便。

我建议的一个很好的选择是100%标题的集合STLSoft C++ Libraries Matthew Wilson(关于C ++的必读书籍的作者)。有便携式外观PlatformSTL可以访问系统特定的API:Windows上的WinSTL和Unix上的UnixSTL,因此它是便携式解决方案。所有特定于系统的元素都使用特征和策略指定,因此它是可扩展的框架。当然还提供了文件系统库。

答案 19 :(得分:0)

Boost Filesystem的initial_path()行为与POSIX的getcwd()相似,既不是你自己想要的,也不是argv[0]加上其中任何一个就应该这样做。

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

我之前使用envp编写了一个解决方案(main()的第三个参数在Linux上工作但在Windows上似乎不可行,所以我基本上推荐与其他人一样的解决方案以前,但附加解释为什么它实际上是正确的,即使结果不是很好。

答案 20 :(得分:0)

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

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

对于标准库,如果Boost足够标准,我会建议使用Boost :: filesystem,但它们似乎已从提案中删除了路径规范化。您可能需要等到TR2 becomes readily available才能获得完全标准的解决方案。

答案 21 :(得分:0)

图书馆解决方案(虽然我知道没有要求)。 如果你碰巧使用Qt: QCoreApplication::applicationDirPath()

答案 22 :(得分:0)

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

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

答案 23 :(得分:0)

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