8 Kasım 2015 Pazar

Dizin İşlemleri - Dizini Dolaşma

Giriş
Dizini dolaşma işleminde her zaman karşımıza çıkan sorunların ilki sadece belirtilen dizinimi dolaşma yoksa alt dizinleri da dahil ederek dolaşma. İkincisi ise dolaşılan dosya ve dizinlerden bir kısmı süzme ve işlememe

İlkinin çözümü zaten kolay. Alt dizinleri de dahil ederek dolaşma için kullanılan basit C# kodu aşağıda. Süzme işlemi için örnekler ise yazını devamında.

void Walk (string directoryPath){
 string[] files = Directory.GetFiles ();
 foreach (string filePath in files){
   ProcessFile (filePath);
 }
 string[] subDirectories = Directory.GetDirectories (directoryPath);
 foreach (string directoryPath in subDirectories){
   Walk (directoryPath);
 }
}

Dizinin Altını Dolaşma
C#
Buraya taşıdım.

Windows
Örnek
WIN32_FIND_DATA findData = {};
HANDLE hFind = ::FindFirstFile("*.txt", &findData);
if (hFind != INVALID_HANDLE_VALUE)
{
  std::cout << findData.cFileName << std::endl;
  while (::FindNextFile(hFind, &findData))
  {
    std::cout << findData.cFileName << std::endl;
  }
  ::CloseHandle(hFind);
}
POSIX
opendir, closedir, readdir, readdir_r ve scandir metodlarını kullanmak mümkün. readdir thread-safe değil. readdir_r thread safe ancak kullanması zor. Kullanması en kolay olan scandir metodu.

opendir
opendir ve readdir İle Dizin Dolaşma yazısına taşıdım.

scandir
scandir bir array'i dolduruyor.Örnek aşağıda
#include <dirent.h>

int main(void)
{
  struct dirent ** namelist = NULL;
  int n = scandir(".", &namelist, NULL, alphasort);
  if (n < 0)
  {
    perror("scandir");
  }
  else
  {
    while (n--) 
    {
      printf("%s\n", namelist[n]->d_name);
      free(namelist[n]);
    }

    free(namelist);
  }
}
ftw (obsolete) ve nftw ile de dolaşmak mümkün.

boost
directory_iterator sınıfı ile verilen dizinin altını dolaşmak mümkün. Örnek :
How to use boost::fs to only load 30 newest files and not the entire directory? sorusunda da cevaplandığı gibi directory_iterator dizini dolaşmak için readdir_r metodunu kullanıyor.
A directory_iterator reads successive elements from the directory for which it was constructed, as if by calling POSIX readdir_r().

How do I count the number of files in a directory using boost::filesystem? sorusunda dizinin recursive_directory_iterator ile recursive bir şekilde de dolaşılması örneği var.
Java
list() metodu ile dizinin altındaki tüm elemanlar alınabiliyor.
Dizinin Altını Süzerek Dolaşma
boost
Not : directory_iterator sınıfına ait leaf() metodu eskiden dolaşılan nesnenin ismini veriyordu ancak artık bu metod kaldırıldı. Bunun yerine iterator->path().filename().string() metodunu kullanmak lazım.

boost ile gelen boost::make_filter_iterator süzerek dolaşma için biçilmiş kaftan. Aşağıdaki örneği How to use boost::fs to only load 30 newest files and not the entire directory? sorusundan aldım.
Bir diğer örnek ise regular expression kullanarak dolaşma. Can I use a mask to iterate files in a directory with Boost? sorusunda örnek verilmiş.

How do I ignore hidden files (and files in hidden directories) with Boost Filesystem? sorusunda ise gizli dizinlerin içine girmeden gezme örneği verilmiş. Dizinin içine girmemek için recursive_directory_iterator sınıfına ait no_push() metodu çağırılıyor.

Bir başka örnekte ise dosyanın uzantısına bakılmış.

for (fs::directory_iterator iter(realPath); iter != end_iter; ++iter )
{
    if (iter->path().extension() == ".png")
    {
    }
}
Directory Iterator sınıfına ait bazı önemli metodlar
path():
directory_iterator sınıfının bazı metodları boost versiyonuna göre değişiklik gösterebiliyor. Eğer versyion 3 kullanılıyorsa path() metodu ile bir path sınıfı döndürüyor.
status():
if (is_directory(dir_itr->status())) {} gibi kullanım imkanı sağlar

Path sınıfına ait bazı önemli metodlar
filename() : Dosyanın ismini ve uzantısını içeren yeni bir path nesnesi döndürür. Örnek:
std::cout << path("/foo/bar.txt").filename().string(); // bar.txt yazar
extension (): Dosyanın uzantısını verir
string() : Path nesnesini string'e çevirir. Örnek. Aynı zamanda yukarıdaki filename() örneğide açıklayıcı.

QT
Walk a directory recursively in QT, skip the folders “.” and “..” sorusuna verilen cevap aşağıdaki gibi. QDir sınıfı kullanılıyor.
void Mainwindow::ReadDir(QString path) {
    //Opens the path
    QDir dir(path);                           
    //skip the folders “.” and “..”
    QFileInfoList files = dir.entryInfoList(QDir::NoDotAndDotDot, QDir::Files|QDir::Dirs);
    //Loops through the found files.
    foreach(const QFileInfo &fi, files)
    {      
        //Gets the absolute file path
        QString Path = fi.absoluteFilePath(); 
        if(fi.isDir())
        {
            //Recursively goes through all the directories.
            ReadDir(Path);          
        }
        else
        {
            //Do stuff with the found file.
        }
    }
}
entryInfoList metodu "sort" seçenekleri ile çalışabiliyor. Örneğin isme ve değişiklik zamanına göre sıralama yapmak için QDir::Name | QDir::Time kullanılabilir.

QDir ile gelen entryList metodu da sort seçenekleri ile çalışabilir.

Java
listFiles() metoduna FileFilter veya FilenameFilter arayüzünü gerçekleştiren bir sınıf geçilebilir. 
 
Uzantısı .java olan dosyaları bulma
File[] files = new File("path").listFiles(new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return name.endsWith(".java");
        }
    });
Buradaki örnekte ise Apache Commons ile gelen ve hem FileFilter hem de FilenameFilter arayüzlerini gerçekleştiren RegexFilter kullanılabilir.

Bir başka örnek ise 
protected void scan(File path, int deepth) {
        File[] files = path.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                scan(file, ++deepth);
            } else {
            //Process file
            }
        }
    }
}
Apache Commons
Apache Commons ile iterator veya liste şeklinde dolaşabilmek mümkün.
FileUtils sınıfı ile Iterator kullanılabilir.Örnek:
Iterator<File> files = FileUtils.iterateFiles(directoryToScan, FileFileFilter.FILE, TrueFileFilter.INSTANCE);
List<String> paths = new ArrayList<String>();
for (File file : files) {
    paths.add(file.getAbsolutePath);
}
Bir diğer örnek ise liste şeklinde veriyor. Liste kullanımına istenirse filtreler de verilebilir. Filtreler RegEx veya uzantı şeklinde olabilir.
File root = new File("/home/myuser/myfolder");
String[] extensions = {"xml"};
boolean recursive = true;
Collection<File> files = FileUtils.listFiles(root, extensions, recursive);
Yukarıdaki örnekle aynı işi yapan bir diğer kod ise burada. DirectoryFileFilter kullanıyor.


Yukarıdaki örnekte listFiles sadece verien uzantıya sahip dosyaları süzerek verir. Hem dosya hem de dizinleri süzerek almak istersek listFilesAndDirs metodu kullanbılabilir. Örnek:


Hiç yorum yok:

Yorum Gönder