আপনি স্ট্যান্ডার্ড সি ++ তে প্রতিটি ফাইল / ডিরেক্টরিতে পুনরাবৃত্তি করবেন কীভাবে?
আপনি স্ট্যান্ডার্ড সি ++ তে প্রতিটি ফাইল / ডিরেক্টরিতে পুনরাবৃত্তি করবেন কীভাবে?
উত্তর:
স্ট্যান্ডার্ড সি ++ এ, প্রযুক্তিগতভাবে এটি করার কোনও উপায় নেই কারণ স্ট্যান্ডার্ড সি ++ এর ডিরেক্টরিগুলির কোনও ধারণা নেই। আপনি যদি নিজের জালটি কিছুটা প্রসারিত করতে চান তবে আপনি বুস্ট.ফাইসিসটেমটি ব্যবহার করতে পছন্দ করতে পারেন । এটি টিআর 2-এ অন্তর্ভুক্তির জন্য গৃহীত হয়েছে, সুতরাং এটি আপনার বাস্তবায়নটিকে যতটা সম্ভব মানের কাছাকাছি রাখার সেরা সুযোগ দেয়।
ওয়েবসাইট থেকে সরাসরি নেওয়া একটি উদাহরণ:
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 ) ) return false;
directory_iterator end_itr; // default construction yields past-the-end
for ( directory_iterator itr( dir_path );
itr != end_itr;
++itr )
{
if ( is_directory(itr->status()) )
{
if ( find_file( itr->path(), file_name, path_found ) ) return true;
}
else if ( itr->leaf() == file_name ) // see below
{
path_found = itr->path();
return true;
}
}
return false;
}
সি ++ 17 এর পরে, <filesystem>
শিরোনাম এবং ব্যাপ্তি- for
, আপনি কেবল এটি করতে পারেন:
#include <filesystem>
using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
...
for (const auto& dirEntry : recursive_directory_iterator(myPath))
std::cout << dirEntry << std::endl;
সি ++ 17 হিসাবে, std::filesystem
স্ট্যান্ডার্ড লাইব্রেরির অংশ এবং এটি <filesystem>
শিরোনামে পাওয়া যাবে (আর "পরীক্ষামূলক" নয়)।
using
, ব্যবহার namespace
পরিবর্তে।
উইন 32 এপিআই ব্যবহার করে আপনি ফাইন্ডফার্সফায়াল এবং ফাইন্ডনেস্টফিল ফাংশন ব্যবহার করতে পারেন ।
http://msdn.microsoft.com/en-us/library/aa365200(VS.85).aspx
ডিরেক্টরিগুলির পুনরাবৃত্তির ট্র্যাভারসাল করার জন্য আপনাকে অবশ্যই FIN_ATTRIBUTE_DIRECTORY বিট সেট আছে কিনা তা পরীক্ষা করতে প্রতিটি WIN32_FIND_DATA.dwFileAributes অবশ্যই পরীক্ষা করতে হবে । যদি বিটটি সেট করা থাকে তবে আপনি সেই ডিরেক্টরিটি পুনরাবৃত্তভাবে ফাংশনটিতে কল করতে পারেন। বিকল্পভাবে আপনি পুনরাবৃত্ত কলের একই প্রভাব সরবরাহের জন্য স্ট্যাক ব্যবহার করতে পারেন তবে খুব দীর্ঘ পথ গাছের জন্য স্ট্যাকের ওভারফ্লো এড়ানো।
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
int main(int argc, char* argv[])
{
vector<wstring> files;
if (ListFiles(L"F:\\cvsrepos", L"*", files)) {
for (vector<wstring>::iterator it = files.begin();
it != files.end();
++it) {
wcout << it->c_str() << endl;
}
}
return 0;
}
আপনি এটি নতুন সি ++ 11 রেঞ্জ ভিত্তিক for
এবং বুস্ট দিয়ে আরও সাধারণ করে তুলতে পারেন :
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
struct recursive_directory_range
{
typedef recursive_directory_iterator iterator;
recursive_directory_range(path p) : p_(p) {}
iterator begin() { return recursive_directory_iterator(p_); }
iterator end() { return recursive_directory_iterator(); }
path p_;
};
for (auto it : recursive_directory_range(dir_path))
{
std::cout << it << std::endl;
}
একটি দ্রুত সমাধান সি এর ডাইরেন্ট.এ লাইব্রেরি ব্যবহার করছে ।
উইকিপিডিয়া থেকে ওয়ার্কিং কোড টুকরা:
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
উপরের উল্লিখিত বুস্ট :: ফাইল সিস্টেমের পাশাপাশি আপনি ডাব্লুএক্সউজেটস :: ডাব্লুএক্সডির এবং কিউটি :: কিউডিআর পরীক্ষা করতে চাইতে পারেন ।
ডাব্লুএক্সউজেডস এবং কিউটি উভয়ই ওপেন সোর্স, ক্রস প্ল্যাটফর্ম সি ++ ফ্রেমওয়ার্ক।
wxDir
পুনরাবৃত্তিমূলকভাবে Traverse()
একটি সহজ GetAllFiles()
ফাংশন ব্যবহার করে ফাইলগুলি ট্র্যাভার করার একটি নমনীয় উপায় সরবরাহ করে । পাশাপাশি আপনি ট্র্যাভারসালটি GetFirst()
এবং GetNext()
ফাংশনগুলি প্রয়োগ করতে পারেন (আমি ধরে নিই যে ট্র্যাভার্স () এবং গেটএলফিলস () হ'ল এমন মোড়ক যা শেষ পর্যন্ত গেটফ্রাস্ট () এবং গেটনেক্সট () ফাংশন ব্যবহার করে)।
QDir
ডিরেক্টরি স্ট্রাকচার এবং তাদের সামগ্রীতে অ্যাক্সেস সরবরাহ করে। কিউডিআর দিয়ে ডিরেক্টরিগুলি অতিক্রম করার বিভিন্ন উপায় রয়েছে। আপনি QDirIterator :: সাবডাইরেক্টরিজ পতাকা দ্বারা ইনস্ট্যান্ট করা হয়েছে এমন QDirIterator সহ ডিরেক্টরি সামগ্র (উপ ডিরেক্টরি সহ) পুনরাবৃত্তি করতে পারেন। আর একটি উপায় হল কিউডিরের গেটইন্ট্রিলিস্ট () ফাংশনটি ব্যবহার করা এবং পুনরাবৃত্তির ট্র্যাভারসাল বাস্তবায়ন করা।
এখানে নমুনা কোড রয়েছে ( এখান থেকে # উদাহরণ 8-5 থেকে নেওয়া ) যা সমস্ত উপ ডিরেক্টরিতে পুনরাবৃত্তি করতে পারে তা দেখায়।
#include <qapplication.h>
#include <qdir.h>
#include <iostream>
int main( int argc, char **argv )
{
QApplication a( argc, argv );
QDir currentDir = QDir::current();
currentDir.setFilter( QDir::Dirs );
QStringList entries = currentDir.entryList();
for( QStringList::ConstIterator entry=entries.begin(); entry!=entries.end(); ++entry)
{
std::cout << *entry << std::endl;
}
return 0;
}
বুস্ট :: ফাইল সিস্টেম পুনরাবৃত্ত_ডাইরেক্টরি_টিরেটর সরবরাহ করে যা এই কাজের জন্য বেশ সুবিধাজনক:
#include "boost/filesystem.hpp"
#include <iostream>
using namespace boost::filesystem;
recursive_directory_iterator end;
for (recursive_directory_iterator it("./"); it != end; ++it) {
std::cout << *it << std::endl;
}
আপনি পসিক্স সিস্টেমে সি বা সি ++ তে একটি ফাইল সিস্টেমের হায়ারার্কি ব্যবহার করতে ftw(3)
বাnftw(3)
হাঁটতে পারেন ।
nftw()
ব্যবহারের জন্য একটি ভাল টিউটোরিয়াল কাজ করে ।
আপনি না। সি ++ স্ট্যান্ডার্ডের ডিরেক্টরিগুলির কোনও ধারণা নেই। স্ট্রিংটিকে একটি ফাইল হ্যান্ডলে পরিণত করা বাস্তবায়নের উপর নির্ভর করে। স্ট্রিংয়ের বিষয়বস্তু এবং এটিতে মানচিত্রগুলি ওএস নির্ভর। মনে রাখবেন যে ওএস লিখতে সি ++ ব্যবহার করা যেতে পারে, সুতরাং এটি এমন একটি স্তরে ব্যবহৃত হয় যেখানে কোনও ডিরেক্টরিতে পুনরাবৃত্তি করতে হবে তা জিজ্ঞাসা করা এখনও সংজ্ঞায়িত হয়নি (কারণ আপনি ডিরেক্টরি পরিচালনা কোডটি লিখছেন)।
এটি কীভাবে করবেন তার জন্য আপনার ওএস এপিআই ডকুমেন্টেশনটি দেখুন। আপনার যদি পোর্টেবল হওয়ার দরকার হয় তবে বিভিন্ন ওএসের জন্য আপনার কাছে একগুচ্ছ # আইফডিফ এস থাকতে হবে ।
আপনি সম্ভবত বুথ বা সি ++ 14 এর পরীক্ষামূলক ফাইল সিস্টেম স্টাফ দিয়ে সেরা হতে পারেন। যদি আপনি কোনও অভ্যন্তরীণ ডিরেক্টরি পার্স করছেন (যেমন প্রোগ্রামটি বন্ধ হওয়ার পরে আপনার প্রোগ্রামের জন্য ডেটা সঞ্চয় করার জন্য ব্যবহৃত হয়), তবে একটি সূচি ফাইল তৈরি করুন যাতে ফাইলের সামগ্রীর সূচি থাকে of যাইহোক, আপনাকে সম্ভবত ভবিষ্যতে বুস্ট ব্যবহার করতে হবে, সুতরাং যদি আপনি এটি ইনস্টল না করে থাকেন তবে এটি ইনস্টল করুন! দ্বিতীয়ত, আপনি শর্তসাপেক্ষ সংকলন ব্যবহার করতে পারেন, যেমন:
#ifdef WINDOWS //define WINDOWS in your code to compile for windows
#endif
প্রতিটি মামলার কোড https://stackoverflow.com/a/67336/7077165 থেকে নেওয়া হয়েছে
#ifdef POSIX //unix, linux, etc.
#include <stdio.h>
#include <dirent.h>
int listdir(const char *path) {
struct dirent *entry;
DIR *dp;
dp = opendir(path);
if (dp == NULL) {
perror("opendir: Path does not exist or could not be read.");
return -1;
}
while ((entry = readdir(dp)))
puts(entry->d_name);
closedir(dp);
return 0;
}
#endif
#ifdef WINDOWS
#include <windows.h>
#include <string>
#include <vector>
#include <stack>
#include <iostream>
using namespace std;
bool ListFiles(wstring path, wstring mask, vector<wstring>& files) {
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
wstring spec;
stack<wstring> directories;
directories.push(path);
files.clear();
while (!directories.empty()) {
path = directories.top();
spec = path + L"\\" + mask;
directories.pop();
hFind = FindFirstFile(spec.c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
return false;
}
do {
if (wcscmp(ffd.cFileName, L".") != 0 &&
wcscmp(ffd.cFileName, L"..") != 0) {
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
directories.push(path + L"\\" + ffd.cFileName);
}
else {
files.push_back(path + L"\\" + ffd.cFileName);
}
}
} while (FindNextFile(hFind, &ffd) != 0);
if (GetLastError() != ERROR_NO_MORE_FILES) {
FindClose(hFind);
return false;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
}
return true;
}
#endif
//so on and so forth.
ফাইল সিস্টেম ট্র্যাভারসাল, যেমন open()
এবং এর জন্য আপনাকে ওএস-নির্দিষ্ট ফাংশনগুলি কল করতে হবে readdir()
। সি স্ট্যান্ডার্ড কোনও ফাইল সিস্টেম সম্পর্কিত ফাংশন নির্দিষ্ট করে না।
আমরা 2019 সালে আছি We আমাদের মধ্যে ফাইল সিস্টেমের স্ট্যান্ডার্ড লাইব্রেরি রয়েছে C++
। Filesystem library
যেমন পাথ, নিয়মিত ফাইল, ও ডিরেক্টরিগুলি হিসাবে ফাইল সিস্টেম এবং তাদের উপাদান, উপর অপারেশন সম্পাদন জন্য সুবিধা প্রদান করে।
আপনি যদি বহনযোগ্যতার বিষয় বিবেচনা করছেন তবে এই লিঙ্কটিতে একটি গুরুত্বপূর্ণ নোট রয়েছে । এটা বলে:
যদি একটি হায়ারার্কিকাল ফাইল সিস্টেম বাস্তবায়নের অ্যাক্সেসযোগ্য না হয় বা এটি প্রয়োজনীয় ক্ষমতা সরবরাহ না করে তবে ফাইল সিস্টেম লাইব্রেরি সুবিধাগুলি অনুপলব্ধ হতে পারে। অন্তর্নিহিত ফাইল সিস্টেম দ্বারা সমর্থন না করা থাকলে কিছু বৈশিষ্ট্য উপলব্ধ নাও থাকতে পারে (যেমন এফএটি ফাইল সিস্টেমে প্রতীকী লিঙ্কের অভাব রয়েছে এবং একাধিক হার্ডলিঙ্ক নিষিদ্ধ করেছে)। এই ক্ষেত্রে ত্রুটিগুলি অবশ্যই রিপোর্ট করতে হবে।
ফাইল সিস্টেম লাইব্রেরিটি মূলত এই হিসাবে বিকাশিত হয়েছিল boost.filesystem
, প্রযুক্তিগত স্পেসিফিকেশন আইএসও / আইইসি টিএস 18822: 2015 হিসাবে প্রকাশিত হয়েছিল এবং অবশেষে সি ++ 17 হিসাবে আইএসও সি ++ এ একীভূত হয়েছিল। বুস্ট বাস্তবায়ন বর্তমানে সি ++ 17 লাইব্রেরির চেয়ে বেশি সংকলক এবং প্ল্যাটফর্মগুলিতে উপলব্ধ।
@ আদি-শবিত এই প্রশ্নের উত্তর দিয়েছেন যখন এটি স্টাড :: পরীক্ষামূলক অংশ ছিল এবং তিনি এই উত্তরটি ২০১ 2017 সালে আপডেট করেছেন I আমি গ্রন্থাগার সম্পর্কে আরও বিশদ দিতে এবং আরও বিশদ উদাহরণ দেখাতে চাই।
std :: ফাইল সিস্টেম :: recursive_directory_iterator এমন একটি LegacyInputIterator
ডিরেক্টরি যা ডিরেক্টরি ডিরেক্টরিতে অন্তর্ভুক্ত হয় এবং সমস্ত উপ-ডিরেক্টরিতে পুনরাবৃত্তভাবে প্রবেশ করে। প্রতিটি ডিরেক্টরি এন্ট্রি একবারে একবার পরিদর্শন করা বাদে পুনরাবৃত্তির ক্রমটি অনির্ধারিত।
আপনি যদি সাব-ডাইরেক্টরিগুলির প্রবেশগুলিতে পুনরাবৃত্তভাবে পুনরাবৃত্তি করতে না চান, তবে ডিরেক্টরি_ iterator ব্যবহার করা উচিত।
উভয় পুনরাবৃত্তির ডিরেক্টরি_তন্ত্রের একটি বস্তু প্রদান করে । directory_entry
মত বিভিন্ন দরকারী সদস্য ফাংশন আছে is_regular_file
, is_directory
, is_socket
, is_symlink
ইত্যাদি path()
সদস্য ফাংশন আয় একটি অবজেক্ট এসটিডি :: ফাইলসিস্টেম :: পাথ এবং এটি পেতে ব্যবহার করা যেতে পারে file extension
, filename
, root name
।
নীচের উদাহরণ বিবেচনা করুন। আমি Ubuntu
টার্মিনালটি ব্যবহার করে এটি ব্যবহার এবং সংকলন করছি
g ++ example.cpp --std = c ++ 17 -lstdc ++ fs -Wall
#include <iostream>
#include <string>
#include <filesystem>
void listFiles(std::string path)
{
for (auto& dirEntry: std::filesystem::recursive_directory_iterator(path)) {
if (!dirEntry.is_regular_file()) {
std::cout << "Directory: " << dirEntry.path() << std::endl;
continue;
}
std::filesystem::path file = dirEntry.path();
std::cout << "Filename: " << file.filename() << " extension: " << file.extension() << std::endl;
}
}
int main()
{
listFiles("./");
return 0;
}
আপনি না। স্ট্যান্ডার্ড সি ++ কোনও ডিরেক্টরি ধারণাটি প্রকাশ করে না। বিশেষত এটি কোনও ডিরেক্টরিতে সমস্ত ফাইল তালিকাভুক্ত করার উপায় দেয় না।
সিস্টেম () কলগুলি ব্যবহার করা এবং ফলাফলগুলি বিশ্লেষণ করা একটি ভয়ঙ্কর হ্যাক। সর্বাধিক যুক্তিসঙ্গত সমাধানটি হ'ল কিছু ধরণের ক্রস-প্ল্যাটফর্ম লাইব্রেরি যেমন কিউটি বা এমনকি পসিক্স ব্যবহার করা ।
আপনি ব্যবহার করতে পারেন std::filesystem::recursive_directory_iterator
। তবে সাবধান থাকুন এর মধ্যে প্রতীকী (নরম) লিঙ্ক রয়েছে। এগুলি এড়াতে চাইলে আপনি ব্যবহার করতে পারেন is_symlink
। ব্যবহারের উদাহরণ:
size_t directorySize(const std::filesystem::path& directory)
{
size_t size{ 0 };
for (const auto& entry : std::filesystem::recursive_directory_iterator(directory))
{
if (entry.is_regular_file() && !entry.is_symlink())
{
size += entry.file_size();
}
}
return size;
}
আপনি যদি উইন্ডোজটিতে থাকেন তবে আপনি FindNextFile API এর সাথে FindFirstFile ব্যবহার করতে পারেন। প্রদত্ত পাথটি কোনও ফাইল বা ডিরেক্টরি কিনা তা পরীক্ষা করতে আপনি FindFileData.dwFileAttributes ব্যবহার করতে পারেন। যদি এটি কোনও ডিরেক্টরি হয় তবে আপনি পুনরাবৃত্তভাবে অ্যালগরিদম পুনরাবৃত্তি করতে পারেন।
এখানে, আমি কিছু কোড একসাথে রেখেছি যা একটি উইন্ডোজ মেশিনে সমস্ত ফাইল তালিকাভুক্ত করে।
ফাইল ট্রি ওয়াক ftw
হ'ল পথটিতে পুরো ডিরেক্টরি গাছটি প্রাচীর করার জন্য একটি পুনরাবৃত্ত উপায়। আরও বিশদ এখানে ।
দ্রষ্টব্য: আপনি fts
এমনটি ব্যবহার করতে পারেন যা লুকানো ফাইলগুলি এড়িয়ে যেতে পারে .
বা ..
বা.bashrc
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <string.h>
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
printf("0%3o\t%s\n", status->st_mode&0777, name);
}
if (type == FTW_D && strcmp(".", name) != 0)
{
printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}
আউটপুট নিম্নলিখিত মত দেখাচ্ছে:
0755 ./Shivaji/
0644 ./Shivaji/20200516_204454.png
0644 ./Shivaji/20200527_160408.png
0644 ./Shivaji/20200527_160352.png
0644 ./Shivaji/20200520_174754.png
0644 ./Shivaji/20200520_180103.png
0755 ./Saif/
0644 ./Saif/Snapchat-1751229005.jpg
0644 ./Saif/Snapchat-1356123194.jpg
0644 ./Saif/Snapchat-613911286.jpg
0644 ./Saif/Snapchat-107742096.jpg
0755 ./Milind/
0644 ./Milind/IMG_1828.JPG
0644 ./Milind/IMG_1839.JPG
0644 ./Milind/IMG_1825.JPG
0644 ./Milind/IMG_1831.JPG
0644 ./Milind/IMG_1840.JPG
আপনি যদি *.jpg, *.jpeg, *.png
একটি নির্দিষ্ট প্রয়োজনের জন্য কোনও ফাইলের নামের (উদাহরণস্বরূপ: সমস্ত ফাইলগুলির সন্ধান করা) ব্যবহার করতে চান তবে আমাদের বলুন fnmatch
।
#include <ftw.h>
#include <stdio.h>
#include <sys/stat.h>
#include <iostream>
#include <fnmatch.h>
static const char *filters[] = {
"*.jpg", "*.jpeg", "*.png"
};
int list(const char *name, const struct stat *status, int type)
{
if (type == FTW_NS)
{
return 0;
}
if (type == FTW_F)
{
int i;
for (i = 0; i < sizeof(filters) / sizeof(filters[0]); i++) {
/* if the filename matches the filter, */
if (fnmatch(filters[i], name, FNM_CASEFOLD) == 0) {
printf("0%3o\t%s\n", status->st_mode&0777, name);
break;
}
}
}
if (type == FTW_D && strcmp(".", name) != 0)
{
//printf("0%3o\t%s/\n", status->st_mode&0777, name);
}
return 0;
}
int main(int argc, char *argv[])
{
if(argc == 1)
{
ftw(".", list, 1);
}
else
{
ftw(argv[1], list, 1);
}
return 0;
}