Comment obtenir une liste de fichiers dans un répertoire afin que chacun puisse être traité?
C++ standard ne fournit pas un moyen de faire cela. Mais boost::filesystem
peut le faire: http://www.boost.org/doc/libs/1_37_0/libs/filesystem/example/simple_ls.cpp
Voici ce que j'utilise:
/* Returns a list of files in a directory (except the ones that begin with a dot) */
void GetFilesInDirectory(std::vector<string> &out, const string &directory)
{
#ifdef WINDOWS
HANDLE dir;
WIN32_FIND_DATA file_data;
if ((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE)
return; /* No files found */
do {
const string file_name = file_data.cFileName;
const string full_file_name = directory + "/" + file_name;
const bool is_directory = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
if (file_name[0] == '.')
continue;
if (is_directory)
continue;
out.Push_back(full_file_name);
} while (FindNextFile(dir, &file_data));
FindClose(dir);
#else
DIR *dir;
class dirent *ent;
class stat st;
dir = opendir(directory);
while ((ent = readdir(dir)) != NULL) {
const string file_name = ent->d_name;
const string full_file_name = directory + "/" + file_name;
if (file_name[0] == '.')
continue;
if (stat(full_file_name.c_str(), &st) == -1)
continue;
const bool is_directory = (st.st_mode & S_IFDIR) != 0;
if (is_directory)
continue;
out.Push_back(full_file_name);
}
closedir(dir);
#endif
} // GetFilesInDirectory
Voici un exemple en C sous Linux. C'est si, vous êtes sous Linux et que cela ne vous dérange pas de faire ce petit peu en ANSI C.
#include <dirent.h>
DIR *dpdf;
struct dirent *epdf;
dpdf = opendir("./");
if (dpdf != NULL){
while (epdf = readdir(dpdf)){
printf("Filename: %s",epdf->d_name);
// std::cout << epdf->d_name << std::endl;
}
}
closedir(dpdf);
Vous devez utiliser les appels du système d'exploitation (par exemple, l'API Win32) ou un wrapper autour d'eux. J'ai tendance à utiliser Boost.Filesystem car c'est une interface supérieure par rapport au gâchis qu'est l'API Win32 (en plus d'être multiplateforme).
Si vous souhaitez utiliser l'API Win32, Microsoft dispose d'une liste de fonctions et exemples sur msdn.
Version C++ 11/Linux:
#include <dirent.h>
if (auto dir = opendir("some_dir/")) {
while (auto f = readdir(dir)) {
if (!f->d_name || f->d_name[0] == '.')
continue; // Skip everything that starts with a dot
printf("File: %s\n", f->d_name);
}
closedir(dir);
}
Si vous utilisez Windows et utilisez MSVC, la bibliothèque MSDN contient le code exemple qui le permet
Et voici le code de ce lien:
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
void ErrorHandler(LPTSTR lpszFunction);
int _tmain(int argc, TCHAR *argv[])
{
WIN32_FIND_DATA ffd;
LARGE_INTEGER filesize;
TCHAR szDir[MAX_PATH];
size_t length_of_arg;
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=0;
// If the directory is not specified as a command-line argument,
// print usage.
if(argc != 2)
{
_tprintf(TEXT("\nUsage: %s <directory name>\n"), argv[0]);
return (-1);
}
// Check that the input path plus 2 is not longer than MAX_PATH.
StringCchLength(argv[1], MAX_PATH, &length_of_arg);
if (length_of_arg > (MAX_PATH - 2))
{
_tprintf(TEXT("\nDirectory path is too long.\n"));
return (-1);
}
_tprintf(TEXT("\nTarget directory is %s\n\n"), argv[1]);
// Prepare string for use with FindFile functions. First, copy the
// string to a buffer, then append '\*' to the directory name.
StringCchCopy(szDir, MAX_PATH, argv[1]);
StringCchCat(szDir, MAX_PATH, TEXT("\\*"));
// Find the first file in the directory.
hFind = FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
ErrorHandler(TEXT("FindFirstFile"));
return dwError;
}
// List all the files in the directory with some info about them.
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
_tprintf(TEXT(" %s <DIR>\n"), ffd.cFileName);
}
else
{
filesize.LowPart = ffd.nFileSizeLow;
filesize.HighPart = ffd.nFileSizeHigh;
_tprintf(TEXT(" %s %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
}
}
while (FindNextFile(hFind, &ffd) != 0);
dwError = GetLastError();
if (dwError != ERROR_NO_MORE_FILES)
{
ErrorHandler(TEXT("FindFirstFile"));
}
FindClose(hFind);
return dwError;
}
void ErrorHandler(LPTSTR lpszFunction)
{
// Retrieve the system error message for the last-error code
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
DWORD dw = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dw,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf,
0, NULL );
// Display the error message and exit the process
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
(lstrlen((LPCTSTR)lpMsgBuf)+lstrlen((LPCTSTR)lpszFunction)+40)*sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf,
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
TEXT("%s failed with error %d: %s"),
lpszFunction, dw, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
LocalFree(lpMsgBuf);
LocalFree(lpDisplayBuf);
}
La résolution de ce problème nécessitera une solution spécifique à la plate-forme. Recherchez opendir () sous unix/linux ou FindFirstFile () sous Windows. Ou bien, de nombreuses bibliothèques gèrent la partie spécifique à la plate-forme.
Je viens de poser une question similaire et voici ma solution basée sur la réponse reçue (en utilisant la bibliothèque boost::filesystem
):
#include <string>
#include <iostream>
#include <boost/filesystem.hpp>
using namespace std;
using namespace 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 in a list
{
cout << i->path().filename().string() << endl;
}
else
continue;
}
}
La sortie est comme:
file1.txt
file2.dat
Après avoir combiné de nombreux extraits, j'ai finalement trouvé une solution réutilisable pour Windows, qui utilise ATL Library, fournie avec Visual Studio.
#include <atlstr.h>
void getFiles(CString directory) {
HANDLE dir;
WIN32_FIND_DATA file_data;
CString file_name, full_file_name;
if ((dir = FindFirstFile((directory + "/*"), &file_data)) == INVALID_HANDLE_VALUE)
{
// Invalid directory
}
while (FindNextFile(dir, &file_data)) {
file_name = file_data.cFileName;
full_file_name = directory + file_name;
if (strcmp(file_data.cFileName, ".") != 0 && strcmp(file_data.cFileName, "..") != 0)
{
std::string fileName = full_file_name.GetString();
// Do stuff with fileName
}
}
}
Pour accéder à la méthode, appelez simplement:
getFiles("i:\\Folder1");
Vous pouvez utiliser le code suivant pour obtenir tous les fichiers d’un répertoire. Une simple modification dans la réponse d’Andreas Bonini pour supprimer l’occurrence de "." et ".."
CString dirpath="d:\\mydir"
DWORD errVal = ERROR_SUCCESS;
HANDLE dir;
WIN32_FIND_DATA file_data;
CString file_name,full_file_name;
if ((dir = FindFirstFile((dirname+ "/*"), &file_data)) == INVALID_HANDLE_VALUE)
{
errVal=ERROR_INVALID_ACCEL_HANDLE;
return errVal;
}
while (FindNextFile(dir, &file_data)) {
file_name = file_data.cFileName;
full_file_name = dirname+ file_name;
if (strcmp(file_data.cFileName, ".") != 0 && strcmp(file_data.cFileName, "..") != 0)
{
m_List.AddTail(full_file_name);
}
}
HANDLE WINAPI FindFirstFile(
__in LPCTSTR lpFileName,
__out LPWIN32_FIND_DATA lpFindFileData
);
Configurez les attributs pour rechercher uniquement les répertoires.
Ou vous faites cela et lisez ensuite le test.txt:
#include <windows.h>
int main() {
system("dir /b > test.txt");
}
Le "/ b" signifie que seuls les noms de fichiers sont retournés, pas d’informations complémentaires.