it-swarm.com.de

Wie kann ich den Dateinamen und die Erweiterung aus einem Pfad in C++ extrahieren?

Ich habe eine Liste von Dateien, die in einem .log in dieser Syntax gespeichert sind:

c:\foto\foto2003\shadow.gif
D:\etc\mom.jpg

Ich möchte den Namen und die Erweiterung aus diesen Dateien extrahieren. Können Sie ein Beispiel für einen einfachen Weg nennen?

60
Octavian

Um einen Dateinamen ohne Erweiterung zu extrahieren, verwenden Sie boost :: filesystem :: path :: stem anstatt hässlichen std :: string :: find_last_of (".")

boost::filesystem::path p("c:/dir/dir/file.ext");
std::cout << "filename and extension : " << p.filename() << std::endl; // file.ext
std::cout << "filename only          : " << p.stem() << std::endl;     // file
148
Nickolay Merkin

Wenn Sie einen sicheren Weg wünschen (d. H. Portabel zwischen Plattformen und keine Annahmen in den Pfad setzen), würde ich empfehlen, boost::filesystem zu verwenden.

Es würde irgendwie so aussehen:

boost::filesystem::path my_path( filename );

Dann können Sie verschiedene Daten aus diesem Pfad extrahieren. Hier ist die Dokumentation des Pfadobjekts.


BTW: Denken Sie auch daran, um pfadähnlich zu verwenden

c:\foto\foto2003\shadow.gif

sie müssen den \ in einem String-Literal entziehen:

const char* filename = "c:\\foto\\foto2003\\shadow.gif";

Oder verwenden Sie stattdessen /:

const char* filename = "c:/foto/foto2003/shadow.gif";

Dies gilt nur für die Angabe von Literalzeichenfolgen in "" Anführungszeichen. Das Problem besteht nicht, wenn Sie Pfade aus einer Datei laden.

19
Kos

Sie müssen Ihre Dateinamen aus der Datei in std::string lesen. Sie können den Zeichenfolgen-Extraktionsoperator von std::ostream verwenden. Wenn Sie Ihren Dateinamen in einem std::string gespeichert haben, können Sie die std::string::find_last_of-Methode verwenden, um das letzte Trennzeichen zu finden.

Etwas wie das:

std::ifstream input("file.log");
while (input)
{
    std::string path;
    input >> path;

    size_t sep = path.find_last_of("\\/");
    if (sep != std::string::npos)
        path = path.substr(sep + 1, path.size() - sep - 1);

    size_t dot = path.find_last_of(".");
    if (dot != std::string::npos)
    {
        std::string name = path.substr(0, dot);
        std::string ext  = path.substr(dot, path.size() - dot);
    }
    else
    {
        std::string name = path;
        std::string ext  = "";
    }
}
14

Für C++ 17

#include <filesystem>

std::filesystem::path p("c:/dir/dir/file.ext");
std::cout << "filename and extension: " << p.filename() << std::endl; // "file.ext"
std::cout << "filename only: " << p.stem() << std::endl;              // "file"

Referenz zum Dateisystem: http://en.cppreference.com/w/cpp/filesystem


Wie von @RoiDanto vorgeschlagen, kann std::out für die Ausgabeformatierung Zitate enthalten, z. B .:

filename and extension: "file.ext"

Sie können std::filesystem::path in std::string durch p.filename().string() konvertieren, wenn Sie dies benötigen, z.

filename and extension: file.ext
11
Yuchen Zhong

Nicht der Code, aber hier ist die Idee:

  1. Lesen Sie einen std::string aus dem Eingabestrom (std::ifstream). Jede gelesene Instanz ist der vollständige Pfad
  2. Führen Sie einen find_last_of für die Zeichenfolge für den \ aus.
  3. Extrahieren Sie einen Teilstring von dieser Position bis zum Ende. Jetzt erhalten Sie den Dateinamen
  4. Führen Sie einen find_last_of für . aus, und eine Unterzeichenfolge auf beiden Seiten gibt Ihnen Namen + Erweiterung.
3
Nim

Die Antworten von Nickolay Merkin und Yuchen Zhong sind großartig, aber den Kommentaren ist zu entnehmen, dass sie nicht ganz genau sind. 

Bei der impliziten Konvertierung in std :: string wird beim Drucken der Dateiname in Anführungszeichen gesetzt. Die Kommentare sind auch nicht korrekt.

path::filename() und path::stem() geben ein neues Pfadobjekt und path::string() eine Referenz auf einen String zurück. Daher könnte etwas wie std::cout << file_path.filename().string() << "\n" Probleme mit der Referenz-Referenz verursachen, da die Zeichenfolge, auf die die Referenz verweist, möglicherweise zerstört wurde.

0

Für Linux- oder Unix-Maschinen verfügt das Betriebssystem über zwei Funktionen, die sich auf Pfad- und Dateinamen beziehen. Verwenden Sie man 3 basename, um weitere Informationen zu diesen Funktionen zu erhalten .. Der Vorteil der Verwendung der vom System bereitgestellten Funktionalität besteht darin, dass Sie keinen Boost installieren oder Ihre eigenen Funktionen schreiben müssen.

#include <libgen.h>
       char *dirname(char *path);
       char *basename(char *path);

Beispielcode aus der Manpage:

   char *dirc, *basec, *bname, *dname;
           char *path = "/etc/passwd";

           dirc = strdup(path);
           basec = strdup(path);
           dname = dirname(dirc);
           bname = basename(basec);
           printf("dirname=%s, basename=%s\n", dname, bname);

Aufgrund des Argumenttyps non-const der Funktion basename () ist es etwas unkompliziert, diesen Code innerhalb von C++ zu verwenden. Hier ist ein einfaches Beispiel aus meiner Code-Basis:

string getFileStem(const string& filePath) const {
   char* buff = new char[filePath.size()+1];
   strcpy(buff, filePath.c_str());
   string tmp = string(basename(buff));
   string::size_type i = tmp.rfind('.');
   if (i != string::npos) {
      tmp = tmp.substr(0,i);
   }
   delete[] buff;
   return tmp;
}

Die Verwendung von Neu/Löschen ist kein guter Stil. Ich hätte es in einen try/catch -Block legen können, falls zwischen den beiden Aufrufen etwas passiert ist. 

0
Kemin Zhou

Ich benutze dieses Snippet auch, um den passenden Schrägstrich zu bestimmen:

boost::filesystem::path slash("/");
    boost::filesystem::path::string_type preferredSlash = slash.make_preferred().native();

und ersetzen Sie dann die Schrägstriche durch den bevorzugten Schrägstrich für das Betriebssystem. Nützlich, wenn ständig zwischen Linux/Windows bereitgestellt wird.

0
svanschalkwyk