Wie bekomme ich das aktuelle Verzeichnis?


70

Ich habe dies in C # und Delphi getan, aber C ++ ist böse. Der Zweck besteht darin, eine Datei im aktuellen Verzeichnis zu erstellen (in dem die ausführbare Datei ausgeführt wird).

Mein Code:

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

Ich erhalte eine Ausnahme bei GetCurrentDirectory ().

Bitte sagen Sie mir, warum ich eine Ausnahme bekomme und wie ich es in C ++ einfacher mache.


2
#include <unistd.h> char * getcwd (char * buf, size_t size); stackoverflow.com/questions/298510/…
Anuswadh


3
Bitte beachten Sie: Das aktuelle Verzeichnis ist nicht immer das Verzeichnis, in dem sich die Exe befindet (z. B. c: \ users \ me> \ dir1 \ dir2 \ runme.exe. Hier befinden Sie sich in c: \ users \ me und führen exe von \ dir1 \ aus dir2).
Merkur

3
"aber C ++ ist böse" hatte mich ziemlich gut lachen lol.
NobleUplift

@ NobleUplift Es ist lustig, weil es wahr ist: D
Aviv Cohn

Antworten:


129

Ich würde empfehlen, ein Buch über C ++ zu lesen, bevor Sie fortfahren, da es hilfreich wäre, einen festeren Stand zu bekommen. Accelerated C ++ von Koenig und Moo ist ausgezeichnet.

Verwenden Sie GetModuleFileName, um den ausführbaren Pfad abzurufen :

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

Hier ist eine C ++ - Funktion, die das Verzeichnis ohne den Dateinamen abruft:

#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
Hinweis, dass Sie möglicherweise ein breites Zeichen wie wchar_t buffer [MAX_PATH] verwenden müssen. in diesen Tagen ...
Rogerdpack

2
OderGetModuleFileNameA
Mikhail

1
Um noch einmal zu wiederholen, was @Mikhail gesagt hat, würden Sie GetModuleFileNameAfür Code, der einen Mehrbyte -Zeichensatz verwendet, und GetModuleFileNameWfür Unicode verwenden. GetModuleFileName(ohne Aoder W) ist eigentlich ein Alias ​​für den Zeichensatz, den Ihr Projekt verwenden soll. So werden die meisten Win32-API-Methoden eingerichtet, die Zeichenfolgen verwenden. Wenn Sie also ein Unicode-Projekt haben und Ihre Zeichenfolgen auch Unicode sind, müssen Sie nur aufrufen GetModuleFileName. Gleiches gilt, wenn Ihr Projekt mehrbyte ist und mehrbyte Zeichenfolgen verwendet.
RectangleEquals

1
Ich mag den Parameter oder die find_last_of()Methode nicht, gibt es keine Konstante, die das Trennzeichen in Verzeichnisnamen definiert, wie "... / ... / ..." oder "... \ ... \. .. "?
Dominique

Dies ist nur

41

GetCurrentDirectory reserviert keinen Platz für das Ergebnis, es liegt an Ihnen, dies zu tun.

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

Werfen Sie auch einen Blick auf Boost.Filesystem Bibliothek , wenn Sie diese der C ++ Art und Weise tun wollen.


Hmm, NPath zeigt auf ein anderes Verzeichnis. Wie kann ich das Verzeichnis anzeigen lassen, in dem sich die ausführbare Datei befindet?
Ivan Prodanov

7
Das aktuelle Verzeichnis ist auch unter C # und Delphi nicht mit dem Verzeichnis der ausführbaren Datei identisch. Vielleicht könnten Sie Ihre Frage klarer machen?

John, das ist etwas komplizierter und kann nicht einfach in einem Kommentar beantwortet werden. Vielleicht solltest du Neils Rat befolgen (beide).
Avakar

25

Die Frage ist nicht klar, ob das aktuelle Arbeitsverzeichnis oder der Pfad des Verzeichnisses mit der ausführbaren Datei gewünscht wird.

Die meisten Antworten scheinen letztere zu beantworten.

Für den ersteren und für den zweiten Teil der Frage der Erstellung der Datei enthält der C ++ 17-Standard jetzt die Dateisystembibliothek, die dies erheblich vereinfacht:

#include <filesystem>
#include <iostream>

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

Dadurch wird das aktuelle Arbeitsverzeichnis abgerufen, der Dateiname zum Pfad hinzugefügt und eine leere Datei erstellt. Beachten Sie, dass das Pfadobjekt die os-abhängige Pfadbehandlung übernimmt, sodass cwd.string () eine os-abhängige Pfadzeichenfolge zurückgibt. Neato.


Wie können wir die Bibliothek <Dateisystem> verwenden, um den Pfad des Verzeichnisses zu erhalten, das die ausführbare Datei enthält?
Ramy Sameh

afaik das <Dateisystem> hat keine einfache Möglichkeit, dies zu tun. Es tut uns leid. Bitte beachten Sie die anderen Antworten für diesen Teil der Frage.
Rasmus Dall

12

IMHO hier sind einige Verbesserungen an Anons Antwort .

#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
Das ist eigentlich anders. Sie geben nicht den Verzeichnispfad an, sondern den Pfad der Datei, einschließlich der Datei.
Dyesdyes

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

Ich habe GetModuleFileName nicht richtig verwendet. Ich fand diese Arbeit sehr gut. gerade unter Windows getestet, noch nicht unter Linux ausprobiert :)


5

Ein einfacher Weg, dies zu tun, ist:

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

argv[]ist so ziemlich ein Array, das Argumente enthält, mit denen Sie die EXE-Datei ausgeführt haben, aber das erste ist immer ein Pfad zur ausführbaren Datei. Wenn ich das baue, zeigt die Konsole: C:\Users\Ulisse\source\repos\altcmd\Debug\currentdir.exe


1
Beste Antwort für seine Einfachheit.
Jerry Switalski

4

Sie sollten einen gültigen Pufferplatzhalter angeben. das ist:

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

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

4

Bitte vergessen Sie nicht, Ihre Puffer auf etwas zu initialisieren , bevor Sie sie verwenden. Und genauso wichtig, geben Sie Ihren String-Puffern Platz für die Endung null

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

Referenz


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- Ein Argument vom Typ "char *"ist nicht kompatibel mit einem Parameter vom Typ "LPWSTR"(Unicode-Codierung)
ZidoX

3

Sie können den Dateinamen auf GetModuleFileName()elegantere Weise entfernen :

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

Ich hoffe es hilft!


2

GetCurrentDirectory () wird das aktuelle Verzeichnis , das ist , wo die exe aufgerufen wird , aus . Verwenden Sie GetModuleFileName (NULL ...), um den Speicherort der Exe abzurufen. Wenn Sie das Handle für die Exe haben, können Sie es von GetCommandLine () ableiten, wenn Sie dies nicht tun.

Wie Mr. Butterworth betont, brauchen Sie keinen Griff.


3
Eigentlich brauchen Sie kein echtes Handle - ein NULL-Handle erhält den Namen der ausführbaren Datei mit dem Pfad.

2

Warum erwägt hier niemand, diesen einfachen Code zu verwenden?

TCHAR szDir[MAX_PATH] = { 0 };

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

oder noch einfacher

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

1

Ich denke, der einfachste Weg, das aktuelle Verzeichnis zu finden, besteht darin, es aus den Befehlszeilenargumenten herauszuschneiden.

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

Möglicherweise wissen Sie, dass jedes Programm seinen ausführbaren Namen als erstes Befehlszeilenargument erhält. Sie können dies also verwenden.


0

Codefragmente aus meinem CAE-Projekt mit Unicode-Entwicklungsumgebung:

/// @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);
}

Verwenden Sie einfach die templete CA2CAEX oder CA2AEX , die die interne API - Aufrufe :: MultiByteToWideChar oder :: WideCharToMultiByte .


0

Wenn Sie die Poco- Bibliothek verwenden, handelt es sich um einen Einzeiler , der meiner Meinung nach auf allen Plattformen funktionieren sollte.

Poco::Path::current()

-1

Um das Verzeichnis zu finden, in dem sich Ihre ausführbare Datei befindet, können Sie Folgendes verwenden:

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

-2
String^ exePath = Application::ExecutablePath;<br>
MessageBox::Show(exePath);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.