Dizin etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
Dizin etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

22 Ağustos 2017 Salı

Dizin İşlemleri

Bu yazıyla ilgili olarak Dosya İşlemleri başlıklı yazıya göz atabilirsiniz. 
Dizin Kopyalama
Apache Commons
FileUtils Sınıfı copyDirectory metodu yazısına taşıdım.

Dizin Silme
C 
rmdir(const char* path) metodu ile sadece boş olan bir dizin silinebilir. Dizin boş değilse hata kodu atanır.
If the directory is not an empty directory, rmdir() shall fail and set errno to [EEXIST] or [ENOTEMPTY]..

boost
boost::filesystem::remove_all() metodu ile verilen dizin ve altındaki diğer dizin ve dosyalar silinirler.
Eğer verilen dizin değil de sadece içi silinsin isteniyorsa aşağıdaki gibi yapılabilir.
Örnek:
namespace fs=boost::filesystem;
fs::path path_to_remove("C:\\DirectoryToRemove");
for(fs::directory_iterator end_dir_it, it(path_to_remove); it!=end_dir_it; ++it) {
  remove_all(it->path());
}
Eğer dizin veya dosya silinemezse bir exception atılır. Bu exception yakalanarak tekrar denemek için aşağıdaki kod kullanılabilir.
 
C#
Directory.Delete (path,true); metodu ile verilen dizin ve altındaki diğer dizin ve dosyalar silinirler

Windows
Shell API kullanılırsa SHFileOperation ile silinebilir. Kullanılmazsa buradaki kod kullanılabilir.

Dizinin Yaratma
C 
#include < sys/stat:h >
if
(mkdir(location.c_str(), S_IRWXU) != 0){
    //hata
}
S_IRWXU read, write, execute by user (owner) anlamına geliyor.
boost

Eğer dizinler iç içe açılacaksa aşağıdaki gibi yapılabilir.

boost::filesystem::create_directories( "c:\\foo\\bar" );
Java
Eğer tek bir dizin açılacaksa File.mkdir() kullanılır. Eğer iç içe dizinler açılacaksa File.mkdirs() kullanılır. Örnek:
File  f = new File("non_existing_dir/someDir");
f.mkdirs()
Windows
if (!CreateDirectory(location.c_str(), NULL) &&
    ERROR_ALREADY_EXISTS != GetLastError())
{
    err << GetLastError();
}
Gizli Dizinin Yaratma
C
Bu iş Unix üzerinde dosya isminin başına . işareti getirilerek yapılıyor. Örnek:

Geçici Dizini Bulma
Çoğu mobil cihazda geçici dizin kavramı yoktur.
C#
Path.GetTempPath() ile geçici dizin bulunabilir. Çağrı sonucunda şuna benzer bir çıktı alırız.
"%USERPROFILE%AppData\Local\Temp"
Geçici Dizin Oluşturma
C
mkdtemp ile geçici dosya oluşturuluyor.

Dizinin Varlığını Kontrol Etme
C
stat  metodu ile dizinin varlığı kontrol edilebilir. Örnek:
if(stat(location.c_str(), &st) != 0){
    //dizin yok
}
boost
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

namespace fs = boost::filesystem;
fs::path somedirectory ("some path");
fs::is_directory(somedirectory);
Bir başka örnek ise
fs::file_status folderStatus =  fs::status("some path");
fs::is_directory(folderStatus) ;  
Dizinin Altını Dolaşma

Dizin İşlemleri - Dizini Dolaşma başlıklı yazıya taşıdım.

Dizinin Büyüklüğünü Bulma
POSIX
Örneği buradan aldım.

int total_size = 0; // Global, to accumulate the size
void* dirsize(void* dir)
{
    DIR* dp=opendir("dirpath");
    // Loop over files in directory
    while ((entry = readdir(dp)) != NULL)
    {
        ...

        // Check if directory
        if (S_ISDIR(statbuf.st_mode))
        {
            dirsize (strcpy (entry->d_name));
        }
        else
        {
            // Add filesize
            total_size += statbuf.st_size;
        }
    }
    closedir(dirp);
}

Özel Dizinler
Özel Dizin İşlemleri yazısına taşıdım.

Exe'nin Bulunduğu Dizini Alma
Tüm işletim sistemlerine mahsus çözümler burada
argv [0] değerini okumak her zaman exe'nin bulunduğu dizini bulmamızı sağlamaz!

Linux
readlink() metodunu kullanarak sembolik link olan /proc/sef/exe okunarak yapılabilir. procfs hakkında bilgi almak için procfs ve tmpfs başlıklı yazıya göz atabilirsiniz.

Örnek:
Bir başka örnek:
char szTmp[32];
sprintf(szTmp, "/proc/%d/exe", getpid());
readlink(szTmp, pBuf, len);
Windows
GetModuleFileName ile yapılıyor.
Örnek
Genel kod için şöyle yaparız.

TCHAR dest[MAX_PATH];
GetThisPath(dest, MAX_PATH);
Örnek
Unicode derlerken şöyle yaparız.

#include <windows.h>
...
WCHAR dirname[1024];
GetModuleFileNameW(NULL, dirname, 1024);
Örnek:
#include <windows.h>
char ownPth[MAX_PATH];
GetModuleFileName(NULL, pBuf, MAX_PATH);
C#
Application.CurrrentDomain.BaseDirectory ile alınabilir.
Application.StartupPath ile de alınabilir.
System.IO.Path.Combine(Application.StartupPath, @"Resources\check_active.png");


Çalışılan Dizini Alma
C  
char *getcwd(char *buf, size_t size); ile programın çalıştığı dizin alınabilir. Örnek:
char* initial_cur_dir = malloc(1000);
getcwd(initial_cur_dir, 1000);
Bu metodun açıklamasında kullanılan şu cümle önemli. Metodun aynı zamanda I/O yapılan dizini gösterdiği de anlatılmış.
This method shall get the default I/O path.

boost
Burada açıklandığı gibi current_path ile şimdiki dizin alınabilir.

QT
QCoreApplication::applicationDirPath() ile programın çalıştığı dizin alınabilir.

C#
Directory.GetCurrentDirectory ile alınabilir.

Çalışılan Dizini Değiştirme
C#
Directory.SetCurrentDirectory metodu ile yapılabilir.

Verilen Dizinin Yolunu Native Olarak Alma
QT
 QDir::fromNativeSeparators ile Windows dizinler Unix tarzına dönüştürülebilir. Örneğin 
QString myUnixPath = QDir::fromNativeSeparators("c:\\winnt\\system32");//c:/winnt/system32
Verilen Göreceli Dizini Tam Dizin Yoluna Çevirme
boost
system_complete ile göreceli olan dizin, tam dizin yoluna çevirilir. Örnek:

Native Dizin Ayracını Alma
QT
QDir::separator() ile alınabilir.
Java
File.sepatator ile alınabilir.

Dizinleri Ekleme
C
Basit bir strcat kullanılabilir. Ancak bu metod buffer overflow hatasına biraz müsait.
ConcatPath(char *fullpath, char *subdir, char *filename)
{
    strcat(fullpath, BASE_PATH);  
    strcat(fullpath, subdir); 
    strcat(fullpath, "/");
    strcat(fullpath, filename);
}

snprintf daha makul bir çözüm
bool build_path(char *dest, size_t size, char *subdir, char *filename)
{
    // Don't assume the input is valid
    if ( (dest == NULL) || (size < 1) || (filename == NULL) ) {
        return false;
    }

    // Make no subdir work  (sane default behavior)
    if ( subdir == NULL ) {
        subdir = "";
    }

    // Prevent buffer overruns by using a safe formatting function
    size_t stored = snprintf(dest, size, BASE_PATH "/%s/%s", subdir, filename);

    // Returns success (true) if the path fit the buffer
    return ((stored+1) <= size);
}


QT
QT ile aşağıdaki kod kullanılabilir. Fonksiyona girdi olan path1, path2 parametreleri teker teker temizlenmiyor. Her birisi "/" ile bitse bile ekleme işlemi sonunda QDir::cleanPath() metodu ile sonuç temizleniyor.
QString appendPath(const QString& path1, const QString& path2)
{
    return QDir::cleanPath(path1 + QDir::separator() + path2);
}
Java
Java 7 ile Paths.get kullanılabilir.

C#
IO.Path.Combine ile dizinler eklenebilir.
var basePath = @"\\server\BaseFolder";
var relativePath = @"\My\Relative\Folder";

var combinedPath = Path.Combine(basePath, relativePath);
Not : Combine metoduna verilen ikinci parametre, yan relative path "\" karakteri ile başlamamalıdır! Başlarsa absolute path olur ve istediğimiz sonucu alamayız.

Daha da ilkel bir yöntem Path.DirectorySeparatorChar kullanarak kendi kendimize eklememiz.
string sound = Application.ExecutablePath + string.Format ("{0}Sounds{0}Finished.wav", Path.DirectorySeparatorChar);

Diskleri Dolaşma
Java
File.listRoots() ile bu iş yapılabiliyor. Örneği buradan aldım.

Böylece C:\\ ile başlayan sabit bir dizin yerine File.listRoots()[0] kullanılabilir.

Diskin Mantıksal Block Büyüklüğünü Bulma
C
Buradaki soruda bu iş için standart bir metod bulunmadığı ancak Linux'ta ioctl, Solaris'te dkio, Windows'ta ise DeviceIoControl kullanılarak yapılabileceği söylenmiş. Örnek:
ioctl(fd, BLKPBSZGET, &block_size);


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: