如何获取当前目录?


70

我已经在C#和Delphi中进行了此操作,但是C ++是邪恶的。目的是在当前目录(正在运行可执行文件的位置)中创建一个文件。

我的代码:

LPTSTR NPath = NULL;
DWORD a = GetCurrentDirectory(MAX_PATH,NPath);
HANDLE hNewFile = CreateFile(NPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

我在GetCurrentDirectory()获得异常。

请告诉我为什么会出现异常,如何使它在C ++中更容易?


2
#include <unistd.h> char * getcwd(char * buf,size_t size); stackoverflow.com/questions/298510/…–
阿努斯瓦德


3
请注意:当前目录并不总是exe所在的目录。(例如c:\ users \ me> \ dir1 \ dir2 \ runme.exe,此处您位于c:\ users \ me中,并且从\ dir1 \运行exe dir2)。
水星

3
“但是C ++是邪恶的”让我笑得很开心。
NobleUplift '16

@NobleUplift这很有趣,因为它是真的:D
Aviv Cohn

Answers:


129

我建议您在继续学习之前阅读一本有关C ++的书,因为这将有助于您站稳脚跟。Koenig和Moo的加速C ++非常出色。

要获取可执行路径,请使用GetModuleFileName

TCHAR buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );

这是一个C ++函数,该函数获取不带文件名的目录:

#include <windows.h>
#include <string>
#include <iostream>

wstring ExePath() {
    TCHAR buffer[MAX_PATH] = { 0 };
    GetModuleFileName( NULL, buffer, MAX_PATH );
    std::wstring::size_type pos = std::wstring(buffer).find_last_of(L"\\/");
    return std::wstring(buffer).substr(0, pos);
}

int main() {
    std::cout << "my directory is " << ExePath() << "\n";
}

5
注意,您可能需要使用宽字符,例如wchar_t buffer [MAX_PATH]; 这些天...
rogerdpack

2
GetModuleFileNameA
Mikhail 2014年

1
要重申@Mikhail所说的内容,您将使用GetModuleFileNameA利用多字节字符集的代码以及GetModuleFileNameWunicode。GetModuleFileName(不带AW)实际上是项目设置要使用的任何字符集的别名,这是设置大多数利用字符串的Win32 API方法的方式。因此,如果您有一个unicode项目,并且您的字符串也是unicode,则只需调用GetModuleFileName。如果您的项目是多字节并且使用多字节字符串,则同样适用。
RectangleEquals

1
我不喜欢参数或find_last_of()方法,没有一些常量在目录名中定义分隔符,例如“ ... / ... / ...”或“ ... \ ... \”。 ..”?
多米尼克

这仅是Windows

41

GetCurrentDirectory 不会为结果分配空间,这取决于您。

TCHAR NPath[MAX_PATH];
GetCurrentDirectory(MAX_PATH, NPath);

另外,如果您想以C ++的方式进行操作,请查看Boost.Filesystem库。


嗯,NPath指向另一个目录,如何显示可执行文件所在的目录?
伊万·普罗达诺夫

7
即使在C#和Delphi下,当前目录也与可执行文件的目录不同。也许您可以使您的问题更清楚?

约翰,涉及的内容更多,不能在评论中简单回答。也许您应该遵循尼尔(两个人)的建议。
avakar,2009年

25

问题尚不清楚,是需要当前工作目录还是包含可执行文件的目录路径。

大多数答案似乎都回答了后者。

但是对于前者以及创建文件问题的第二部分,C ++ 17标准现在合并了文件系统库,这大大简化了这一过程:

#include <filesystem>
#include <iostream>

std::filesystem::path cwd = std::filesystem::current_path() / "filename.txt";
std::ofstream file(cwd.string());
file.close();

这将获取当前工作目录,将文件名添加到路径并创建一个空文件。请注意,路径对象负责操作系统相关的路径处理,因此cwd.string()返回操作系统相关的路径字符串。Neato。


我们如何使用<filesystem>库获取包含可执行文件的目录的路径?
拉米·萨默

afaik <filesystem>没有做到这一点的直接方法。抱歉。请参阅该部分问题的其他答案。
拉斯莫斯·多尔(Rasmus Dall)”

12

恕我直言,这是对匿名答案的一些改进。

#include <windows.h>
#include <string>
#include <iostream>

std::string GetExeFileName()
{
  char buffer[MAX_PATH];
  GetModuleFileName( NULL, buffer, MAX_PATH );
  return std::string(buffer);
}

std::string GetExePath() 
{
  std::string f = GetExeFileName();
  return f.substr(0, f.find_last_of( "\\/" ));
}

2
这实际上是不同的。您不提供目录路径,而是提供文件的路径,包括文件。
dysdyes 2015年

6
#include <iostream>    
#include <stdio.h>
#include <dirent.h>

std::string current_working_directory()
{
    char* cwd = _getcwd( 0, 0 ) ; // **** microsoft specific ****
    std::string working_directory(cwd) ;
    std::free(cwd) ;
    return working_directory ;
}

int main(){
    std::cout << "i am now in " << current_working_directory() << endl;
}

我无法正确使用GetModuleFileName。我发现这项工作做得很好。刚刚在Windows上测试过,尚未在Linux上尝试过:)


5

一个简单的方法是:

int main(int argc, char * argv[]){
    std::cout << argv[0]; 
    std::cin.get();
}

argv[]几乎是一个包含运行.exe的参数的数组,但是第一个始终是可执行文件的路径。如果我进行构建,控制台将显示: C:\Users\Ulisse\source\repos\altcmd\Debug\currentdir.exe


1
简洁的最佳答案。
杰里·斯瓦塔尔​​斯基

4

您应该提供一个有效的缓冲区占位符。那是:

TCHAR s[100];
DWORD a = GetCurrentDirectory(100, s);

4
WCHAR path[MAX_PATH] = {0};
GetModuleFileName(NULL, path, MAX_PATH);
PathRemoveFileSpec(path);

4

在使用它们之前,请不要忘记将缓冲区初始化为某种东西。同样重要的是,为字符串缓冲区留出结尾为null的空间

TCHAR path[MAX_PATH+1] = L"";
DWORD len = GetCurrentDirectory(MAX_PATH, path);

参考


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

1
currentDir-类型"char *"的参数与类型的参数"LPWSTR"(Unicode编码)不兼容
ZidoX

3

您可以GetModuleFileName()使用更简洁的方式从中删除文件名:

TCHAR fullPath[MAX_PATH];
TCHAR driveLetter[3];
TCHAR directory[MAX_PATH];
TCHAR FinalPath[MAX_PATH];
GetModuleFileName(NULL, fullPath, MAX_PATH);
_splitpath(fullPath, driveLetter, directory, NULL, NULL);
sprintf(FinalPath, "%s%s",driveLetter, directory);

希望能帮助到你!


2

GetCurrentDirectory()获取当前目录,这是从中调用exe的位置。若要获取exe的位置,请使用GetModuleFileName(NULL ...)。如果您拥有该exe的句柄,或者没有该句柄,则可以从GetCommandLine()派生它。

正如巴特沃思先生指出的那样,您不需要把手。


3
实际上,您不需要真正的句柄-NULL句柄可获取带有路径的可执行文件名。

2

为什么这里没有人考虑使用此简单代码?

TCHAR szDir[MAX_PATH] = { 0 };

GetModuleFileName(NULL, szDir, MAX_PATH);
szDir[std::string(szDir).find_last_of("\\/")] = 0;

甚至更简单

TCHAR szDir[MAX_PATH] = { 0 };
TCHAR* szEnd = nullptr;
GetModuleFileName(NULL, szDir, MAX_PATH);
szEnd = _tcsrchr(szDir, '\\');
*szEnd = 0;

1

我猜想,找到当前目录的最简单方法是从命令行args删除它。

#include <string>
#include <iostream>

int main(int argc, char* argv[])
{
  std::string cur_dir(argv[0]);
  int pos = cur_dir.find_last_of("/\\");

  std::cout << "path: " << cur_dir.substr(0, pos) << std::endl;
  std::cout << "file: " << cur_dir.substr(pos+1) << std::endl;
  return 0;
}

您可能知道每个程序都将其可执行文件名作为第一个命令行参数。这样就可以使用了。


0

来自我的带有Unicode开发环境的CAE项目的代码片段:

/// @brief Gets current module file path. 
std::string getModuleFilePath() {
    TCHAR buffer[MAX_PATH];
    GetModuleFileName( NULL, buffer, MAX_PATH );
    CT2CA pszPath(buffer);
    std::string path(pszPath);
    std::string::size_type pos = path.find_last_of("\\/");
    return path.substr( 0, pos);
}

只需使用模版CA2CAEXCA2AEX即可调用内部API :: MultiByteToWideChar:: WideCharToMultiByte



-1

要查找可执行文件所在的目录,可以使用:

TCHAR szFilePath[_MAX_PATH];
::GetModuleFileName(NULL, szFilePath, _MAX_PATH);

-2
String^ exePath = Application::ExecutablePath;<br>
MessageBox::Show(exePath);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.