如何获取当前目录?

103

我想在当前目录(即可执行文件所在的位置)创建一个文件。

我的代码:

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

我在使用GetCurrentDirectory()时遇到了异常。

为什么会出现异常?


3
#include <unistd.h> char *getcwd(char *buf, size_t size);这段代码是C语言中用于获取当前工作目录的函数。使用该函数需要包含头文件"unistd.h",传入一个指向字符数组的指针buf和数组长度size。函数会将当前工作目录的路径名存储在buf中,并返回该指针。如果执行成功,函数返回值与buf相同;否则,返回NULL。 - Anuswadh
5
请注意:当前目录并不总是exe所在的目录。(例如:c:\users\me> \dir1\dir2\runme.exe,这时你在 c:\users\me 目录下运行位于 \dir1\dir2\ 目录中的exe文件。) - Mercury
3
空指针 - 你会得到一个访问冲突。 - hfrmobile
1
你必须将两个参数都设置为零!!!为了确定所需的缓冲区大小,请将此参数设置为NULL,将nBufferLength参数设置为0。如果nBufferLength> 0且缓冲区指针为NULL-->可能会出现访问冲突。 - hfrmobile
1
由于空指针,可能会发生段错误 - 它没有指向任何内存,因此对其进行解引用可能会导致崩溃(这就是函数内发生的情况)。 - Gregor Hartl Watters
显示剩余4条评论
24个回答

154
我建议在继续之前先阅读一本关于C++的书籍,这将有助于您更好地掌握基础。Koenig和Moo的Accelerated C++非常优秀。
要获取可执行路径,请使用GetModuleFileName
TCHAR buffer[MAX_PATH] = { 0 };
GetModuleFileName( NULL, buffer, MAX_PATH );

这是一个获取目录而不包含文件名的C++函数:
#include <windows.h>
#include <string>
#include <iostream>

std::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
3
或者 GetModuleFileNameA - Mikhail
3
重申@Mikhail所说的,如果您的代码使用多字节字符集,则使用GetModuleFileNameA,如果使用Unicode,则使用GetModuleFileNameWGetModuleFileName(没有AW)实际上是一个别名,它根据您的项目设置的字符集来使用,这就是大多数使用字符串的Win32 API方法的设置方式。因此,如果您的项目是Unicode,并且您的字符串也是Unicode,则只需调用GetModuleFileName即可。如果您的项目是多字节的并且使用多字节字符串,则同样适用。 - RectangleEquals
1
我不喜欢这个参数或 find_last_of() 方法,难道没有一些常量来定义目录名称中的分隔符,比如 ".../.../..." 或者 "........." 吗? - Dominique
1
这仅适用于Windows操作系统。 - user12581835
显示剩余3条评论

93
问题并不清楚是想要当前工作目录还是包含可执行文件的目录路径。
大多数答案似乎回答的是后者。
但是对于前者,以及关于创建文件的问题的第二部分,C++17标准现在包含了filesystem库,它大大简化了这个过程。
#include <filesystem>
#include <iostream>

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

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

1
我们如何使用<filesystem>库来获取包含可执行文件的目录路径? - Ramy Sameh
据我所知,<filesystem> 没有直接的方法来做到这一点。很抱歉。请查看其他答案以获取该问题的解决方案。 - Rasmus Dall
问题的主题是“如何获取当前目录?” - hfrmobile

51

GetCurrentDirectory 不为结果分配空间,这需要由你自己完成。

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

如果您想用C++的方式处理文件系统,请查看Boost.Filesystem库。


嗯,NPath指向另一个目录,我该如何使它显示可执行文件所在的目录? - Ivan Prodanov
8
当前目录与可执行文件的目录不同,即使在 C# 和 Delphi 中也是如此。或许您可以让问题更清晰些? - anon
John,这需要更多的涉及,不能简单地在评论中回答。也许你应该遵循Neil的建议(两个都)。 - avakar

24

一个简单的方法是:

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

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


4
简单明了的最佳答案。 - Jerry Switalski
2
注意:这不会随程序运行而更新,因此它只告诉程序从哪里运行,而不一定是当前工作目录。 - JStrahl
1
GetCurrentDirectory 返回进程的当前目录,即工作目录。 argv [0] 是可执行文件的路径。一个不同之处在于,在进程的生命周期中,工作目录可以更改,而 argv [0] 不能更改。 - Reza Ghodsi

14

依我之见,这里有一些对Anon回答的改进建议。

#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
这实际上是不同的。您不提供目录路径,而是提供包括文件在内的文件路径。 - dyesdyes

9
#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上试过 :)


6

在使用缓冲区之前,请不要忘记将其初始化为某些值。同样重要的是,为您的字符串缓冲区留出结尾空字符的空间。

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

Reference


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

4
你应该提供一个有效的缓冲区占位符,即:

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

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接