Ich habe eine Liste von Dateien in a .log
in dieser Syntax gespeichert :
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 geben, dies zu tun?
std::experimental::filesystem
respstd::filesystem
. Siehe Beitrag von Yuchen Zhong unten.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 für die Ausgabeformatierung vorgeschlagen,
std::out
kann die Ausgabe mit Anführungszeichen umgeben sein, z.filename and extension: "file.ext"
Sie können konvertieren
std::filesystem::path
zustd::string
durch ,p.filename().string()
wenn das ist , was Sie brauchen, zum Beispiel:filename and extension: file.ext
quelle
std::filesystem::path
nach zu konvertieren ,std::string
um ihn verwenden zu könnenstd::cout
. en.cppreference.com/w/cpp/filesystem/path/filename Wenn Sie jedoch etwas anderes denken, können Sie den Beitrag jederzeit kommentieren oder erneut bearbeiten.std::cout
kann sich auf implizite Konvertierung verlassen. Da die Kommentare nachstd::cout
file.ext und file jedoch entweder.string()
zu den Kommentaren hinzugefügt werden müssen oder "file.ext" und "file" sein sollten. Mit Visual C ++ gibt es zwar keinen Unterschied (auch ohnestring()
die Ausgabe ohne Anführungszeichen), aber mit gcc 6.1 erfolgt die Ausgabe mit Anführungszeichen, wenn sie.string()
weggelassen wird. Siehe coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3Wenn Sie einen sicheren Weg suchen (dh zwischen Plattformen portabel und keine Annahmen auf den Pfad setzen), würde ich die Verwendung empfehlen
boost::filesystem
.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.
Übrigens: Denken Sie auch daran, um Pfad wie zu verwenden
Sie müssen das
\
in einem String-Literal entkommen :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 tritt nicht auf, wenn Sie Pfade aus einer Datei laden.quelle
Sie müssen Ihre Dateinamen aus der Datei in lesen
std::string
. Sie können den String-Extraktionsoperator von verwendenstd::ostream
. Sobald Sie Ihren Dateinamen in a habenstd::string
, können Sie diestd::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 = ""; } }
quelle
Nicht der Code, aber hier ist die Idee:
std::string
aus dem Eingabestream (std::ifstream
), jede gelesene Instanz ist der vollständige Pfadfind_last_of
auf der Schnur für die\
find_last_of
für.
, und ein Teilstring auf beiden Seiten gibt Ihnen Name + Erweiterung.quelle
/
. Und ich weiß nicht einmal, ob es mehr Einschränkungen bei den Pfadspezifikationen gibt, daher ist mein Denken einfach - wenn es eine gute Bibliothek gibt, die das tut, was ich will, sollte ich sie verwenden, weil sie mein Ziel wahrscheinlich besser erreichen wird, als ich kann. ;)boost::insects::disperser<T>
generische Vorlage? :)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.
quelle
Für Linux- oder Unix-Computer verfügt das Betriebssystem über zwei Funktionen, die sich mit Pfad- und Dateinamen befassen. Verwenden Sie den Basisnamen man 3, um weitere Informationen zu diesen Funktionen zu erhalten. Der Vorteil der Verwendung der vom System bereitgestellten Funktionen besteht darin, dass Sie keinen Boost installieren oder eigene 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 nicht konstanten Argumenttyps der Funktion basename () ist die Verwendung dieses C ++ - Codes etwas unkompliziert. Hier ist ein einfaches Beispiel aus meiner Codebasis:
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 new / delete ist kein guter Stil. Ich hätte es in einen Try / Catch-Block stecken können, falls zwischen den beiden Aufrufen etwas passiert wäre.
quelle
Versuchen Sie den folgenden Trick, um den Dateinamen aus dem Pfad ohne Erweiterung in C ++ ohne externe Bibliotheken in C ++ zu extrahieren:
#include <iostream> #include <string> using std::string; string getFileName(const string& s) { char sep = '/'; #ifdef _WIN32 sep = '\\'; #endif size_t i = s.rfind(sep, s.length()); if (i != string::npos) { string filename = s.substr(i+1, s.length() - i); size_t lastindex = filename.find_last_of("."); string rawname = filename.substr(0, lastindex); return(rawname); } return(""); } int main(int argc, char** argv) { string path = "/home/aymen/hello_world.cpp"; string ss = getFileName(path); std::cout << "The file name is \"" << ss << "\"\n"; }
quelle
Die Antworten von Nickolay Merkin und Yuchen Zhong sind großartig, aber aus den Kommentaren geht hervor, dass sie nicht ganz korrekt sind.
Bei der impliziten Konvertierung in std :: string beim Drucken wird der Dateiname in Anführungszeichen gesetzt. Die Kommentare sind auch nicht korrekt.
path::filename()
undpath::stem()
gibt ein neues Pfadobjekt zurück undpath::string()
gibt einen Verweis auf eine Zeichenfolge zurück. So etwas wiestd::cout << file_path.filename().string() << "\n"
könnte Probleme mit der baumelnden Referenz verursachen, da die Zeichenfolge, auf die die Referenz verweist, möglicherweise zerstört wurde.quelle