@chrish - Ja, aber dieser hat den Klassiker "Ich darf das 'ls' nicht ausführen"! Es ist genau , wie ich 1. Jahr der Informatik fühlen würde. ; D <3 x
James Bedford
1
C und C ++ sind nicht dieselbe Sprache. Daher ist das Verfahren zur Ausführung dieser Aufgabe in beiden Sprachen unterschiedlich. Bitte wählen Sie eine aus und markieren Sie sie entsprechend neu.
MD XF
2
Und keine dieser Sprachen (außer C ++ seit C ++ 17) hat überhaupt ein Konzept eines Verzeichnisses - daher hängt jede Antwort wahrscheinlich von Ihrem Betriebssystem oder von den Abstraktionsbibliotheken ab, die Sie möglicherweise verwenden.
Toby Speight
Antworten:
809
Bei kleinen und einfachen Aufgaben verwende ich keinen Boost, sondern dirent.h, das auch für Windows verfügbar ist:
DIR *dir;struct dirent *ent;if((dir = opendir ("c:\\src\\"))!= NULL){/* print all the files and directories within directory */while((ent = readdir (dir))!= NULL){
printf ("%s\n", ent->d_name);}
closedir (dir);}else{/* could not open directory */
perror ("");return EXIT_FAILURE;}
Es ist nur eine kleine Header-Datei und erledigt die meisten einfachen Dinge, die Sie benötigen, ohne einen großen vorlagenbasierten Ansatz wie Boost zu verwenden (nichts für ungut, ich mag Boost!).
Der Autor der Windows-Kompatibilitätsebene ist Toni Ronkko. In Unix ist es ein Standardheader.
UPDATE 2017 :
In C ++ 17 gibt es jetzt eine offizielle Möglichkeit, Dateien Ihres Dateisystems aufzulisten : std::filesystem. Es gibt eine ausgezeichnete Antwort von Shreevardhan unten mit diesem Quellcode:
@ArtOfWarfare: tinydir wurde nicht einmal erstellt, als diese Frage beantwortet wurde. Es ist auch ein Wrapper um dirent (POSIX) und FindFirstFile (Windows), während dirent.h nur dirent für Windows umschließt. Ich denke, es ist ein persönlicher Geschmack, aber dirent.h fühlt sich eher als Standard an
Peter Parker
7
@JoshC: weil * ent nur ein zurückgegebener Zeiger der internen Darstellung ist. Wenn Sie das Verzeichnis schließen, wird auch das * ent entfernt. Da das * ent nur zum Lesen gedacht ist, ist dies ein vernünftiges Design, denke ich.
Peter Parker
42
Leute werden echt !! Dies ist eine Frage aus dem Jahr 2009 und es wurde nicht einmal VS erwähnt. Kritisieren Sie also nicht, dass Ihre vollständig proprietäre (wenn auch recht nette) IDE keine jahrhundertealten Betriebssystemstandards unterstützt. Meine Antwort besagte auch, dass es für Windows "verfügbar" ist und ab sofort und für alle Zeiten in keiner IDE "enthalten" ist. Ich bin mir ziemlich sicher, dass Sie dirent herunterladen und in ein include-Verzeichnis und voila einfügen können, da es ist.
Peter Parker
6
Die Antwort ist irreführend. Es sollte beginnen mit: " ... ich verwende dirent.h , für das es auch eine Windows Open Source-Kompatibilitätsschicht gibt ".
Rustyx
10
Mit C ++ 14 gibt es std::experimental::filesystem, mit C ++ 17 gibt es std::filesystem. Siehe Antwort von Shreevardhan unten. Es werden also keine Bibliotheken von Drittanbietern benötigt.
AFAIK kann auch in C ++ 14 verwendet werden, ist dort aber noch experimentell : namespace fs = std::experimental::filesystem;. Es scheint aber in Ordnung zu funktionieren.
PeterK
7
Dies sollte die bevorzugte Antwort für die aktuelle Verwendung sein (beginnend mit C ++ 17)
grüne Diode
4
Heed beim Passieren std::filesystem::pathzu std::cout, werden die Anführungszeichen in der Ausgabe enthalten. Um dies zu vermeiden, hängen Sie .string()an den Pfad an, um eine explizite anstelle einer impliziten Konvertierung durchzuführen (hier std::cout << p.string() << std::endl;). Beispiel: coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
Roi Danton
2
Was ist mit NON-ASCII-Zeichen in Dateinamen? Sollte nicht std::wstringverwendet werden oder was ist der Typ vom Iterator?
Anddero
2
Ich bin mir nicht sicher, ob ich alleine bin, aber ohne Link zu -lstdc++fswürde ich eine bekommen SIGSEGV (Address boundary error). Ich konnte nirgendwo in der Dokumentation feststellen, dass dies erforderlich war, und der Linker gab auch keinen Hinweis. Dies funktionierte sowohl für g++ 8.3.0als auch clang 8.0.0-3. Hat jemand einen Einblick, wo solche Dinge in den Dokumenten / Spezifikationen angegeben sind?
Swalog
229
Leider definiert der C ++ - Standard keine Standardmethode für die Arbeit mit Dateien und Ordnern auf diese Weise.
Die folgende Funktion durchsucht das Verzeichnis und seine Unterverzeichnisse unter Angabe eines Verzeichnispfads und eines Dateinamens rekursiv nach dem Dateinamen und gibt einen Bool und bei Erfolg den Pfad zu der gefundenen Datei zurück.
bool find_file(const path & dir_path,// in this directory,const std::string& file_name,// search for this name,
path & path_found)// placing path here if found{if(!exists(dir_path))returnfalse;
directory_iterator end_itr;// default construction yields past-the-endfor(directory_iterator itr(dir_path); itr != end_itr;++itr){if(is_directory(itr->status())){if(find_file(itr->path(), file_name, path_found))returntrue;}elseif(itr->leaf()== file_name)// see below{
path_found = itr->path();returntrue;}}returnfalse;}
Mit C ++ 14 gibt es std::experimental::filesystem, mit C ++ 17 gibt std::filesystemes ähnliche Funktionen wie boost (die Bibliotheken werden von boost abgeleitet). Siehe Antwort von Shreevardhan unten.
Diese Lösung ist plattformspezifisch. Aus diesem Grund benötigen Sie Bibliotheken von Drittanbietern.
Kraxor
9
@kraxor Ja, es funktioniert nur unter Windows, aber OP verlangt nie nach einer plattformübergreifenden Lösung. Übrigens bevorzuge ich immer etwas ohne Verwendung von 3rd-Libraries (wenn möglich).
Herohuyongtao
7
@herohuyongtao OP hat nie eine Plattform angegeben, und es kann irreführend sein, eine stark plattformabhängige Lösung für eine allgemeine Frage anzugeben. (Was ist, wenn es eine einzeilige Lösung gibt, die nur auf PlayStation 3 funktioniert? Ist das hier eine gute Antwort?) Ich sehe, dass Sie Ihre Antwort so bearbeitet haben, dass sie nur unter Windows funktioniert. Ich denke, das ist in Ordnung.
Kraxor
1
@herohuyongtao OP erwähnte, dass er ls nicht analysieren kann, was bedeutet, dass er wahrscheinlich unter Unix ist. Trotzdem eine gute Antwort für Windows.
Thomas
2
Am Ende habe ich ein std::vector<std::wstring>und dann fileName.c_str()anstelle eines Vektors von Zeichenfolgen verwendet, die nicht kompiliert werden konnten.
PerryC
51
Überprüfen Sie dies für eine Nur-C-Lösung. Es ist nur ein zusätzlicher Header erforderlich:
Sehr schöner Vorschlag. Ich habe es noch nicht auf einem Windows-Computer getestet, aber es funktioniert hervorragend unter OS X.
ArtOfWarfare
Die Bibliothek unterstützt std :: string nicht, daher können Sie file.c_str () nicht an tinydir_open übergeben. In diesem Fall wird beim Kompilieren auf msvc 2015 der Fehler C2664 ausgegeben.
Stepan Yakovenko
33
Ich empfehle die Verwendung globmit diesem wiederverwendbaren Wrapper. Es werden vector<string>entsprechende Dateipfade generiert , die zum Glob-Muster passen:
Ich möchte glob.h wie von Ihnen empfohlen verwenden. Trotzdem kann ich die .h-Datei nicht einschließen: Es heißt No such file or directory. Können Sie mir bitte sagen, wie ich dieses Problem lösen kann?
Tofuw
Beachten Sie, dass diese Routine nur eine Ebene tief ist (keine Rekursion). Es wird auch nicht schnell überprüft, ob es sich um eine Datei oder ein Verzeichnis handelt. Dies können Sie einfach tun, indem Sie GLOB_TILDEmit GLOB_TILDE | GLOB_MARKPfaden wechseln und dann nach Pfaden suchen, die mit einem Schrägstrich enden. Sie müssen beide Änderungen vornehmen, wenn Sie dies benötigen.
Volomike
Ist das plattformübergreifend kompatibel?
Nikhil Augustine
Leider können Sie keine einheitlich versteckten Dateien über finden glob.
LmTinyToon
23
Hier ist ein sehr einfacher Code für die C++11Verwendung der boost::filesystemBibliothek zum Abrufen von Dateinamen in einem Verzeichnis (ohne Ordnernamen):
#include<string>#include<iostream>#include<boost/filesystem.hpp>usingnamespace std;usingnamespace boost::filesystem;int main(){
path p("D:/AnyFolder");for(auto i = directory_iterator(p); i != directory_iterator(); i++){if(!is_directory(i->path()))//we eliminate directories{
cout << i->path().filename().string()<< endl;}elsecontinue;}}
struct dirent {ino_t d_ino;/* inode number */off_t d_off;/* offset to the next dirent */unsignedshort d_reclen;/* length of this record */unsignedchar d_type;/* type of file */char d_name[256];/* filename */};
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - Von der Überprüfung
ice1000
@ ice1000 Ernsthaft? Diese Q & A ist von 2009
Tim
8
Schauen Sie sich diese Klasse an, die die Win32-API verwendet. Erstellen foldernameSie einfach eine Instanz, indem Sie die gewünschte Instanz angeben, und rufen Sie dann die getNextFileMethode auf, um die nächste filenameaus dem Verzeichnis abzurufen. Ich denke es braucht windows.hund stdio.h.
classFileGetter{
WIN32_FIND_DATAA found;
HANDLE hfind;char folderstar[255];int chk;public:FileGetter(char* folder){
sprintf(folderstar,"%s\\*.*",folder);
hfind =FindFirstFileA(folderstar,&found);//skip .FindNextFileA(hfind,&found);}int getNextFile(char* fname){//skips .. when called for the first time
chk=FindNextFileA(hfind,&found);if(chk)
strcpy(fname, found.cFileName);return chk;}};
Manchmal ist es auch gut, direkt zur Quelle zu gehen (Wortspiel beabsichtigt). Sie können viel lernen, indem Sie sich die Innereien einiger der häufigsten Befehle unter Linux ansehen. Ich habe einen einfachen Spiegel der GNU-Coreutils auf Github eingerichtet (zum Lesen).
Shreevardhan Antwort funktioniert großartig. Wenn Sie es jedoch in C ++ 14 verwenden möchten, nehmen Sie einfach eine Änderung vornamespace fs = experimental::filesystem;
dh
#include<string>#include<iostream>#include<filesystem>usingnamespace std;namespace fs = experimental::filesystem;int main(){string path ="C:\\splits\\";for(auto& p : fs::directory_iterator(path))
cout << p << endl;int n;
cin >> n;}
-1. string2wchar_tGibt die Adresse einer lokalen Variablen zurück. Außerdem sollten Sie wahrscheinlich die in WinAPI verfügbaren Konvertierungsmethoden verwenden, anstatt Ihre eigenen zu schreiben.
Daniel Kamil Kozar
3
Diese Implementierung verwirklicht Ihren Zweck und füllt dynamisch ein Array von Zeichenfolgen mit dem Inhalt des angegebenen Verzeichnisses.
int exploreDirectory(constchar*dirpath,char***list,int*numItems){struct dirent **direntList;int i;
errno =0;if((*numItems = scandir(dirpath,&direntList, NULL, alphasort))==-1)return errno;if(!((*list)= malloc(sizeof(char*)*(*numItems)))){
fprintf(stderr,"Error in list allocation for file list: dirpath=%s.\n", dirpath);exit(EXIT_FAILURE);}for(i =0; i <*numItems; i++){(*list)[i]= stringDuplication(direntList[i]->d_name);}for(i =0; i <*numItems; i++){
free(direntList[i]);}
free(direntList);return0;}
Wie würde ich das nennen? Ich erhalte Segfaults, wenn ich versuche, diese Funktion im ersten ifBlock auszuführen . Ich rufe es mitchar **list; int numItems; exploreDirectory("/folder",list, numItems);
Hal T
2
Das funktioniert bei mir. Es tut mir leid, wenn ich mich nicht an die Quelle erinnern kann. Es ist wahrscheinlich von einer Manpage.
Mit std :: experimental :: filesystem :: directory_iterator () können Sie alle Dateien direkt in Ihrem Stammverzeichnis abrufen. Lesen Sie dann den Namen dieser Pfaddateien.
Diese Antwort sollte für Windows-Benutzer funktionieren, bei denen Probleme mit Visual Studio mit einer der anderen Antworten aufgetreten sind.
Laden Sie die Datei dirent.h von der Github-Seite herunter. Es ist jedoch besser, einfach die Datei Raw dirent.h zu verwenden und die folgenden Schritte auszuführen (so habe ich sie zum Laufen gebracht).
Gehen Sie zu Ihrem Projekt und fügen Sie ein neues Element hinzu ( Ctrl+ Shift+ A). Fügen Sie eine Header-Datei (.h) hinzu und nennen Sie sie dirent.h.
Fügen Sie die folgende void filefinder()Methode in Ihren Code ein und rufen Sie sie von Ihrer mainFunktion aus auf oder bearbeiten Sie die Funktion so, wie Sie sie verwenden möchten.
#include<stdio.h>#include<string.h>#include"dirent.h"string path ="C:/folder";//Put a valid path here for foldervoid filefinder(){
DIR *directory = opendir(path.c_str());struct dirent *direntStruct;if(directory != NULL){while(direntStruct = readdir(directory)){
printf("File Name: %s\n", direntStruct->d_name);//If you are using <stdio.h>//std::cout << direntStruct->d_name << std::endl; //If you are using <iostream>}}
closedir(directory);}
BEARBEITEN: Diese Antwort sollte als Hack betrachtet werden, aber sie funktioniert wirklich (wenn auch plattformspezifisch), wenn Sie keinen Zugang zu eleganteren Lösungen haben.
Ich darf den Befehl 'ls' nicht ausführen und die Ergebnisse in meinem Programm analysieren. Ich wusste, dass es jemanden geben würde, der so etwas senden würde ...
yyny
1
Da Dateien und Unterverzeichnisse eines Verzeichnisses im Allgemeinen in einer Baumstruktur gespeichert sind, besteht eine intuitive Möglichkeit darin, den DFS-Algorithmus zu verwenden, um jedes von ihnen rekursiv zu durchlaufen. Hier ist ein Beispiel für ein Windows-Betriebssystem unter Verwendung der grundlegenden Dateifunktionen in io.h. Sie können diese Funktionen auf einer anderen Plattform ersetzen. Was ich ausdrücken möchte, ist, dass die Grundidee von DFS dieses Problem perfekt erfüllt.
#include<io.h>#include<iostream.h>#include<string>usingnamespace std;voidTraverseFilesUsingDFS(conststring& folder_path){_finddata_t file_info;string any_file_pattern = folder_path +"\\*";intptr_t handle = _findfirst(any_file_pattern.c_str(),&file_info);//If folder_path exsist, using any_file_pattern will find at least two files "." and "..", //of which "." means current dir and ".." means parent dirif(handle ==-1){
cerr <<"folder path not exist: "<< folder_path << endl;exit(-1);}//iteratively check each file or sub_directory in current folderdo{string file_name=file_info.name;//from char array to string//check whtether it is a sub direcotry or a fileif(file_info.attrib & _A_SUBDIR){if(file_name !="."&& file_name !=".."){string sub_folder_path = folder_path +"\\"+ file_name;TraverseFilesUsingDFS(sub_folder_path);
cout <<"a sub_folder path: "<< sub_folder_path << endl;}}else
cout <<"file name: "<< file_name << endl;}while(_findnext(handle,&file_info)==0);//
_findclose(handle);}
Ich habe versucht, dem Beispiel in beiden Antworten zu folgen, und es könnte erwähnenswert sein, dass es so aussieht, als ob std::filesystem::directory_entryes geändert wurde, um keine Überlastung des <<Operators zu haben. Stattdessen musste std::cout << p << std::endl;ich Folgendes verwenden, um es kompilieren und zum Laufen bringen zu können:
Wenn Sie wissen, dass Sie nur Multibyte verwenden WIN32_FIND_DATAA, können Sie FindFirstFileAund verwenden FindNextFileA. Dann müssen Sie das Ergebnis nicht in Multibyte oder die Eingabe in Unicode konvertieren.
Kiran Thilak
0
Nur etwas, das ich teilen möchte und danke für das Lesematerial. Spielen Sie ein bisschen mit der Funktion herum, um sie zu verstehen. Es könnte dir gefallen. e stand für Erweiterung, p steht für Pfad und s steht für Pfadtrennzeichen.
Wenn der Pfad ohne Ende des Trennzeichens übergeben wird, wird ein Trennzeichen an den Pfad angehängt. Wenn für die Erweiterung eine leere Zeichenfolge eingegeben wird, gibt die Funktion alle Dateien zurück, deren Name keine Erweiterung enthält. Wenn ein einzelner Stern eingegeben wurde, werden alle Dateien im Verzeichnis zurückgegeben. Wenn die Länge e größer als 0 ist, aber kein einzelnes * ist, wird e ein Punkt vorangestellt, wenn e keinen Punkt an der Nullposition enthalten hat.
Für einen Rückgabewert. Wenn eine Karte mit der Länge Null zurückgegeben wird, wurde nichts gefunden, aber das Verzeichnis war in Ordnung geöffnet. Wenn der Index 999 über den Rückgabewert verfügbar ist, die Kartengröße jedoch nur 1 beträgt, bedeutet dies, dass beim Öffnen des Verzeichnispfads ein Problem aufgetreten ist.
Beachten Sie, dass diese Funktion aus Effizienzgründen in drei kleinere Funktionen unterteilt werden kann. Darüber hinaus können Sie eine Aufruferfunktion erstellen, die anhand der Eingabe erkennt, welche Funktion aufgerufen werden soll. Warum ist das effizienter? Wenn Sie alles abrufen möchten, was eine Datei ist, wird bei dieser Methode die Unterfunktion, die zum Abrufen aller Dateien erstellt wurde, nur alle Dateien abrufen und muss nicht jedes Mal, wenn eine Datei gefunden wird, eine andere unnötige Bedingung auswerten.
Dies gilt auch, wenn Sie Dateien abrufen, die keine Erweiterung haben. Eine bestimmte zu diesem Zweck erstellte Funktion würde nur dann das Wetter bewerten, wenn es sich bei dem gefundenen Objekt um eine Datei handelt und ob der Name der Datei einen Punkt enthält oder nicht.
Das Speichern ist möglicherweise nicht viel, wenn Sie nur Verzeichnisse mit weniger Dateien lesen. Wenn Sie jedoch eine große Menge an Verzeichnissen lesen oder wenn das Verzeichnis einige hunderttausend Dateien enthält, kann dies eine enorme Einsparung bedeuten.
#include<stdio.h>#include<sys/stat.h>#include<iostream>#include<dirent.h>#include<map>
std::map<int, std::string> getFile(std::string p, std::string e ="",unsignedchar s ='/'){if( p.size()>0){if(p.back()!= s) p += s;}if( e.size()>0){if( e.at(0)!='.'&&!(e.size()==1&& e.at(0)=='*')) e ="."+ e;}
DIR *dir;struct dirent *ent;struct stat sb;
std::map<int, std::string> r ={{999,"FAILED"}};
std::string temp;int f =0;bool fd;if((dir = opendir(p.c_str()))!= NULL ){
r.erase (999);while((ent = readdir (dir))!= NULL){
temp = ent->d_name;
fd = temp.find(".")!= std::string::npos?true:false;
temp = p + temp;if(stat(temp.c_str(),&sb)==0&& S_ISREG(sb.st_mode)){if( e.size()==1&& e.at(0)=='*'){
r[f]= temp;
f++;}else{if(e.size()==0){if( fd ==false){
r[f]= temp;
f++;}continue;}if(e.size()> temp.size())continue;if( temp.substr(temp.size()- e.size())== e ){
r[f]= temp;
f++;}}}}
closedir(dir);return r;}else{return r;}}void printMap(auto&m){for(constauto&p : m){
std::cout <<"m["<< p.first <<"] = "<< p.second << std::endl;}}int main(){
std::map<int, std::string> k = getFile("./","");
printMap(k);return0;}
Das hat bei mir funktioniert. Es schreibt eine Datei mit nur den Namen (kein Pfad) aller Dateien. Dann liest es diese txt-Datei und druckt sie für Sie aus.
stat()
Fehler 'Keine solche Datei oder kein solches Verzeichnis', wenn der Dateiname von zurückgegeben wirdreaddir()
.Antworten:
Bei kleinen und einfachen Aufgaben verwende ich keinen Boost, sondern dirent.h, das auch für Windows verfügbar ist:
Es ist nur eine kleine Header-Datei und erledigt die meisten einfachen Dinge, die Sie benötigen, ohne einen großen vorlagenbasierten Ansatz wie Boost zu verwenden (nichts für ungut, ich mag Boost!).
Der Autor der Windows-Kompatibilitätsebene ist Toni Ronkko. In Unix ist es ein Standardheader.
UPDATE 2017 :
In C ++ 17 gibt es jetzt eine offizielle Möglichkeit, Dateien Ihres Dateisystems aufzulisten :
std::filesystem
. Es gibt eine ausgezeichnete Antwort von Shreevardhan unten mit diesem Quellcode:quelle
std::experimental::filesystem
, mit C ++ 17 gibt esstd::filesystem
. Siehe Antwort von Shreevardhan unten. Es werden also keine Bibliotheken von Drittanbietern benötigt.C ++ 17 hat jetzt eine
std::filesystem::directory_iterator
, die als verwendet werden kannAuch
std::filesystem::recursive_directory_iterator
kann iterieren Unterverzeichnisse als auch.quelle
namespace fs = std::experimental::filesystem;
. Es scheint aber in Ordnung zu funktionieren.std::filesystem::path
zustd::cout
, werden die Anführungszeichen in der Ausgabe enthalten. Um dies zu vermeiden, hängen Sie.string()
an den Pfad an, um eine explizite anstelle einer impliziten Konvertierung durchzuführen (hierstd::cout << p.string() << std::endl;
). Beispiel: coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3std::wstring
verwendet werden oder was ist der Typ vom Iterator?-lstdc++fs
würde ich eine bekommenSIGSEGV (Address boundary error)
. Ich konnte nirgendwo in der Dokumentation feststellen, dass dies erforderlich war, und der Linker gab auch keinen Hinweis. Dies funktionierte sowohl fürg++ 8.3.0
als auchclang 8.0.0-3
. Hat jemand einen Einblick, wo solche Dinge in den Dokumenten / Spezifikationen angegeben sind?Leider definiert der C ++ - Standard keine Standardmethode für die Arbeit mit Dateien und Ordnern auf diese Weise.
Da es keinen plattformübergreifenden Weg gibt, ist es am besten, eine Bibliothek wie das Boost-Dateisystemmodul zu verwenden .
Plattformübergreifende Boost-Methode:
Quelle von der oben erwähnten Boost-Seite.
Für Unix / Linux-basierte Systeme:
Sie können opendir / readdir / closedir verwenden .
Quellcode aus den obigen Manpages.
Für ein Windows-basiertes System:
Sie können die Win32-API-Funktionen FindFirstFile / FindNextFile / FindClose verwenden.
Quellcode von den obigen msdn-Seiten.
quelle
FindFirstFile(TEXT("D:\\IMAGE\\MYDIRECTORY\\*"), &findFileData);
std::experimental::filesystem
, mit C ++ 17 gibtstd::filesystem
es ähnliche Funktionen wie boost (die Bibliotheken werden von boost abgeleitet). Siehe Antwort von Shreevardhan unten.Eine Funktion reicht aus, Sie müssen keine Bibliothek eines Drittanbieters (für Windows) verwenden.
PS: Wie von @Sebastian erwähnt, können Sie zu wechseln
*.*
,*.ext
um nur die EXT-Dateien (dh eines bestimmten Typs) in diesem Verzeichnis abzurufen .quelle
std::vector<std::wstring>
und dannfileName.c_str()
anstelle eines Vektors von Zeichenfolgen verwendet, die nicht kompiliert werden konnten.Überprüfen Sie dies für eine Nur-C-Lösung. Es ist nur ein zusätzlicher Header erforderlich:
https://github.com/cxong/tinydir
Einige Vorteile gegenüber anderen Optionen:
readdir_r
wo verfügbar, was bedeutet, dass es (normalerweise) threadsicher istUNICODE
Makrosquelle
Ich empfehle die Verwendung
glob
mit diesem wiederverwendbaren Wrapper. Es werdenvector<string>
entsprechende Dateipfade generiert , die zum Glob-Muster passen:Was dann mit einem normalen System-Platzhaltermuster aufgerufen werden kann, wie zum Beispiel:
quelle
No such file or directory
. Können Sie mir bitte sagen, wie ich dieses Problem lösen kann?GLOB_TILDE
mitGLOB_TILDE | GLOB_MARK
Pfaden wechseln und dann nach Pfaden suchen, die mit einem Schrägstrich enden. Sie müssen beide Änderungen vornehmen, wenn Sie dies benötigen.glob
.Hier ist ein sehr einfacher Code für die
C++11
Verwendung derboost::filesystem
Bibliothek zum Abrufen von Dateinamen in einem Verzeichnis (ohne Ordnernamen):Die Ausgabe ist wie folgt:
quelle
boost::filesystem
Bibliothek boost.org/doc/libs/1_58_0/libs/filesystem/doc/index.htmWarum nicht verwenden
glob()
?quelle
Ich denke, das folgende Snippet kann verwendet werden, um alle Dateien aufzulisten.
Es folgt die Struktur des Strukturverzeichnisses
quelle
Versuchen Sie Boost für die X-Plattform-Methode
http://www.boost.org/doc/libs/1_38_0/libs/filesystem/doc/index.htm
oder verwenden Sie einfach Ihr betriebssystemspezifisches Dateimaterial.
quelle
Schauen Sie sich diese Klasse an, die die Win32-API verwendet. Erstellen
foldername
Sie einfach eine Instanz, indem Sie die gewünschte Instanz angeben, und rufen Sie dann diegetNextFile
Methode auf, um die nächstefilename
aus dem Verzeichnis abzurufen. Ich denke es brauchtwindows.h
undstdio.h
.quelle
GNU Handbuch FTW
http://www.gnu.org/software/libc/manual/html_node/Simple-Directory-Lister.html#Simple-Directory-Lister
Manchmal ist es auch gut, direkt zur Quelle zu gehen (Wortspiel beabsichtigt). Sie können viel lernen, indem Sie sich die Innereien einiger der häufigsten Befehle unter Linux ansehen. Ich habe einen einfachen Spiegel der GNU-Coreutils auf Github eingerichtet (zum Lesen).
https://github.com/homer6/gnu_coreutils/blob/master/src/ls.c
Möglicherweise wird Windows nicht angesprochen, aber mit diesen Methoden können einige Fälle der Verwendung von Unix-Varianten auftreten.
Ich hoffe, das hilft...
quelle
Shreevardhan Antwort funktioniert großartig. Wenn Sie es jedoch in C ++ 14 verwenden möchten, nehmen Sie einfach eine Änderung vor
namespace fs = experimental::filesystem;
dh
quelle
quelle
Ich hoffe dieser Code hilft Ihnen.
quelle
string2wchar_t
Gibt die Adresse einer lokalen Variablen zurück. Außerdem sollten Sie wahrscheinlich die in WinAPI verfügbaren Konvertierungsmethoden verwenden, anstatt Ihre eigenen zu schreiben.Diese Implementierung verwirklicht Ihren Zweck und füllt dynamisch ein Array von Zeichenfolgen mit dem Inhalt des angegebenen Verzeichnisses.
quelle
if
Block auszuführen . Ich rufe es mitchar **list; int numItems; exploreDirectory("/folder",list, numItems);
Das funktioniert bei mir. Es tut mir leid, wenn ich mich nicht an die Quelle erinnern kann. Es ist wahrscheinlich von einer Manpage.
quelle
Mit std :: experimental :: filesystem :: directory_iterator () können Sie alle Dateien direkt in Ihrem Stammverzeichnis abrufen. Lesen Sie dann den Namen dieser Pfaddateien.
quelle
Diese Antwort sollte für Windows-Benutzer funktionieren, bei denen Probleme mit Visual Studio mit einer der anderen Antworten aufgetreten sind.
Laden Sie die Datei dirent.h von der Github-Seite herunter. Es ist jedoch besser, einfach die Datei Raw dirent.h zu verwenden und die folgenden Schritte auszuführen (so habe ich sie zum Laufen gebracht).
Github-Seite für dirent.h für Windows: Github-Seite für dirent.h
Raw Dirent-Datei: Raw dirent.h-Datei
Gehen Sie zu Ihrem Projekt und fügen Sie ein neues Element hinzu ( Ctrl+ Shift+ A). Fügen Sie eine Header-Datei (.h) hinzu und nennen Sie sie dirent.h.
Fügen Sie den Raw dirent.h Datei - Code in der Kopfzeile.
Fügen Sie "dirent.h" in Ihren Code ein.
Fügen Sie die folgende
void filefinder()
Methode in Ihren Code ein und rufen Sie sie von Ihrermain
Funktion aus auf oder bearbeiten Sie die Funktion so, wie Sie sie verwenden möchten.quelle
System nennen es!
Dann lesen Sie einfach die Datei.
BEARBEITEN: Diese Antwort sollte als Hack betrachtet werden, aber sie funktioniert wirklich (wenn auch plattformspezifisch), wenn Sie keinen Zugang zu eleganteren Lösungen haben.
quelle
Da Dateien und Unterverzeichnisse eines Verzeichnisses im Allgemeinen in einer Baumstruktur gespeichert sind, besteht eine intuitive Möglichkeit darin, den DFS-Algorithmus zu verwenden, um jedes von ihnen rekursiv zu durchlaufen. Hier ist ein Beispiel für ein Windows-Betriebssystem unter Verwendung der grundlegenden Dateifunktionen in io.h. Sie können diese Funktionen auf einer anderen Plattform ersetzen. Was ich ausdrücken möchte, ist, dass die Grundidee von DFS dieses Problem perfekt erfüllt.
quelle
Ich habe versucht, dem Beispiel in beiden Antworten zu folgen, und es könnte erwähnenswert sein, dass es so aussieht, als ob
std::filesystem::directory_entry
es geändert wurde, um keine Überlastung des<<
Operators zu haben. Stattdessen musstestd::cout << p << std::endl;
ich Folgendes verwenden, um es kompilieren und zum Laufen bringen zu können:Der Versuch, sich selbst weiterzugeben
p
,std::cout <<
führte zu einem fehlenden Überlastungsfehler.quelle
Aufbauend auf dem, was herohuyongtao gepostet hat, und einigen anderen Posts:
http://www.cplusplus.com/forum/general/39766/
Was ist der erwartete Eingabetyp von FindFirstFile?
Wie konvertiere ich wstring in string?
Dies ist eine Windows-Lösung.
Da ich std :: string übergeben und einen Vektor von Strings zurückgeben wollte, musste ich einige Konvertierungen vornehmen.
quelle
WIN32_FIND_DATAA
, können SieFindFirstFileA
und verwendenFindNextFileA
. Dann müssen Sie das Ergebnis nicht in Multibyte oder die Eingabe in Unicode konvertieren.Nur etwas, das ich teilen möchte und danke für das Lesematerial. Spielen Sie ein bisschen mit der Funktion herum, um sie zu verstehen. Es könnte dir gefallen. e stand für Erweiterung, p steht für Pfad und s steht für Pfadtrennzeichen.
Wenn der Pfad ohne Ende des Trennzeichens übergeben wird, wird ein Trennzeichen an den Pfad angehängt. Wenn für die Erweiterung eine leere Zeichenfolge eingegeben wird, gibt die Funktion alle Dateien zurück, deren Name keine Erweiterung enthält. Wenn ein einzelner Stern eingegeben wurde, werden alle Dateien im Verzeichnis zurückgegeben. Wenn die Länge e größer als 0 ist, aber kein einzelnes * ist, wird e ein Punkt vorangestellt, wenn e keinen Punkt an der Nullposition enthalten hat.
Für einen Rückgabewert. Wenn eine Karte mit der Länge Null zurückgegeben wird, wurde nichts gefunden, aber das Verzeichnis war in Ordnung geöffnet. Wenn der Index 999 über den Rückgabewert verfügbar ist, die Kartengröße jedoch nur 1 beträgt, bedeutet dies, dass beim Öffnen des Verzeichnispfads ein Problem aufgetreten ist.
Beachten Sie, dass diese Funktion aus Effizienzgründen in drei kleinere Funktionen unterteilt werden kann. Darüber hinaus können Sie eine Aufruferfunktion erstellen, die anhand der Eingabe erkennt, welche Funktion aufgerufen werden soll. Warum ist das effizienter? Wenn Sie alles abrufen möchten, was eine Datei ist, wird bei dieser Methode die Unterfunktion, die zum Abrufen aller Dateien erstellt wurde, nur alle Dateien abrufen und muss nicht jedes Mal, wenn eine Datei gefunden wird, eine andere unnötige Bedingung auswerten.
Dies gilt auch, wenn Sie Dateien abrufen, die keine Erweiterung haben. Eine bestimmte zu diesem Zweck erstellte Funktion würde nur dann das Wetter bewerten, wenn es sich bei dem gefundenen Objekt um eine Datei handelt und ob der Name der Datei einen Punkt enthält oder nicht.
Das Speichern ist möglicherweise nicht viel, wenn Sie nur Verzeichnisse mit weniger Dateien lesen. Wenn Sie jedoch eine große Menge an Verzeichnissen lesen oder wenn das Verzeichnis einige hunderttausend Dateien enthält, kann dies eine enorme Einsparung bedeuten.
quelle
quelle
Das hat bei mir funktioniert. Es schreibt eine Datei mit nur den Namen (kein Pfad) aller Dateien. Dann liest es diese txt-Datei und druckt sie für Sie aus.
quelle