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.

Ivan Prodanov
quelle
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";
}
Der maskierte Rebell
quelle
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.

Avakar
quelle
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.

Rasmus Dall
quelle
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( "\\/" ));
}
cdiggins
quelle
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 :)

MsLate
quelle
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


quelle
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);
yves Baumes
quelle
4
WCHAR path[MAX_PATH] = {0};
GetModuleFileName(NULL, path, MAX_PATH);
PathRemoveFileSpec(path);
Zhi Wang
quelle
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

Jj Rivero
quelle
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);
}
freezotic
quelle
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!

ProXicT
quelle
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.

nickd
quelle
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;
123iamking
quelle
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.

zexUlt
quelle
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 .

user3782257
quelle
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()
James Selvakumar
quelle
-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);
Andomar
quelle
-2
String^ exePath = Application::ExecutablePath;<br>
MessageBox::Show(exePath);
Ali
quelle