Dosya ve Klasör erişimi

Makro yazarken zaman zaman dosyaların/klasörlerin adını değiştirmek, taşımak, kopyalamak, silmek v.b gibi manipule edici; bazen de bunların adını, bulunduğu klasörü, adresini, dosya uzantısını öğrenmek v.b gibi bilgi edinici işlemler yapmak isteriz.
Bu tür işlemler için iki temel modül var. FileSystemObject(FSO olarak anılacak) Class Modülü ve FileSystem(FS) Modülü.
FS normal bir modül olduğu için bunlardaki fonksiyonları doğrudan kullanabiliyoruz. O yüzden FSO ile yapacak başka işlemimiz yoksa her zaman FS fonksiyonlarını tercih etmeliyiz, tabi FS ile yapılamayan işlemleri de mecburen FSO ile yapmamız gerekecektir.
Şimdi bunlara detaylıca bakalım. (Her zaman olduğu gibi sadece işimize yarayan veya yarama ihtimali olan üyelere bakıyor olacağız. Ayrıca başka sayfanın konusu olan üyelere o sayfalarda yer vereceğiz.)
NOT:Klasör/Dosya açma/seçme v.s gibi işlemleri bu bölümde değil burada görüyoruz.

Giriş

FSO nesnesi, web server üzerinde VBScript diliyle kullanılmak için yaratılmıştır (ancak tabii ki VBA dünyasından da kullanıma girmiştir). Bu yüzden ayrı bir dll (library) içinde bulunur: Scripting Runtime. Bu nesneyi kullanabilmek için Tools > Reference menüsünden aşağıdaki gibi eklemek gerekir (Tabii ki bu iş early binding için geçerli, late binding için böyle bir işleme gerek yoktur).

post-thumb

Late binding için ise aşağıdaki gibi bir kod yeterli olacaktır. Ancak biz kodlarımızda genellikle early binding kullanacağımız için devam etmeden önce bu library'yi eklemenizi tavsiye ederim.

                    
                            Set FSO = CreateObject("Scripting.FileSystemObject") 'Late binding
                                
                                
Nesne Hiyerarşisi

Dosya işlemleriyle ilgili olarak tepede FSO objesi bulunmaktadır. FSO kendi altında sırasıyla şu nesneleri ve collectionları bulundurur:

  • Drive(s)
  • Folder(s)
  • File(s)
  • TextStream

FSO'yu doğrudan kullanmak yerine ya bu alt nesneleri üretmek için veya bu nesneleri temsil eden string ifadeler üzerinden işlem yapmak için kullanırız.

Mesela bir klasörü silmek için ya FSO'nun DeleteFolder metodunu kullanıp parametre olarak da ilgili klasörün adresini yazarız, ya da GetFolder metodu ile bir Folder nesnesi yaratıp, sonra bu Folder nesnesinin Delete metodunu kullanırız.

Yalnız Folder nesnesini yaratırken dikkatli olmak lazım. Eğer ki, üzerinde çalıştığınız dosyada aynı zamanda Outlook library'si için de referans tanımladıysanız, onun da bir Folder class'ı vardır. İki class'ın karışmaması ve hata almamanız için Folder class'ının önüne library adını yazmamız gerekir: Scripting.Folder şeklinde.

Zaten şu şekilde ikisi arasındaki ayrımı görmek kolaydır:

                    
                        Dim fld As Scripting.Folder
                        Dim outfld As Folder 'outlook folder, bunu kullanmayacağız
                            
                            

İki değişkenin de intellisense'ine baktığımızda çıkan üyelerin farklı olduğunu görüyoruz.

Dosya Klasörü olan Folder'ın üyeleri böyle iken:

post-thumb

Outlook Klasörü olan Folder'ın üyeleri böyledir:

post-thumb

Madem ki bu nesneyi doğrudan kullanmayacağız, ikide bir bu nesneden yaratmamak için bunu global seviyede public olarak tanımlamak akıllıca olacaktır. Global tanımlamayacaksak her prosedürün sonunda buna Nothing değerini atamak bellek yönetimi açısından iyi olacaktır.

Şimdi bu silme işlemine ait örneğe bakalım:

                    
                        Public fso As New FileSystemObject 'global tanımlama
                        Sub foldersil()
                            Dim fld As Scripting.Folder
                            Dim outfld As Folder 'outlook folder, bunu kullanmayacağız

                            fso.DeleteFolder "C:\Users\Volkan\Desktop\sil1"
                            Set fld = fso.GetFolder("C:\Users\Volkan\Desktop\sil2")
                            fld.Delete
                        End Sub
                            
                            
Metodlar

FSO'nun en sık kullanacağımız 2 temel metodu şöyledir:

  • GetFolder: Folder (Klasör) nesnesi döndürür.
  • GetFile: File (Dosya) nesnesi döndürür.

Bu ikisinden başka metodlar da var tabii ama bu ikisinin özelliği, diğer 2 temel nesneyi yaratıyor olmaları.

Bu nesnenin metodlarına daha genel bir bakış ise şöyle olacaktır:

Metodlar Görevleri
GetDrive, GetFolder, GetFile Yukarda bahsettik.
CreateFolder, CreateTextFile Yeni klasör ve dosya yaratır.
DeleteFile, DeleteFolder Klasör ve Dosya siler
CopyFile, CopyFolder Klasör ve Dosya kopyalar
MoveFile, MoveFolder Klasör ve Dosya taşır
DriveExists, FolderExists, FileExists İlgili birim mevcut mu kontrolü yapar

Not:FSO işlemlerinde ilgili dosya/klasör adresi verilirken son karakterin "/" olup olmaması önem arz etmemektedir. Yani "C:\deneme" ile "C:\deneme\" özdeştir (Ancak daha aşağıda göreceğimiz gibi "Dir" ile kullanırken durum farklıdır).

Folder ve File İşlemleri

Folder/File işlemlerinde akılda tutulması gereken en önemli şey, öncelikle dosyanın var olup olmadığını öğrenmeye çalışmaktır. Dosya özellikle Application.FileDialog ile kullanıcıya seçtirilmemişse bu kontrol işlemini mutlaka yapın derim (FileDialog ile yapılan seçimlerde bu kontrole gerek yoktur).

Var mı? Kontrolü

Bunun için FileExists ve FolderExists metotlarını kullanırız:

                    
                        Sub kontrol_fso()
                            If fso.FileExists("C:\Users\Volkan\Desktop\denemeler\deneme.xlsx") Then
                                Debug.Print "Dosya var"
                            End If

                            If fso.FolderExists("C:\Users\Volkan\Desktop\denemeler\") Then 'sonda \ olup olmaması farketmez
                                Debug.Print "Klasör var"
                            End If
                        End Sub
                            
                            
Klasör İçindeki Klasörleri Elde Etme

Bu işlem için SubFolders property'si kullanılır, bu özellik bize Folders collection'ı döndürür. Gerisi ForEach yapmaktan ibarettir:

                    
                            Sub KlasördekiKlasörler()
                                Dim anaklasorStr As String
                                Dim fol As Folder, alt As Folder

                                anaklasorStr = "C:\Users\Volkan\OneDrive\Dökümanlar"
                                Set fol = fso.GetFolder(anaklasorStr)

                                For Each alt In fol.SubFolders
                                    Debug.Print alt.Name
                                    'diğer fso işlemleri
                                Next
                            End Sub
                                
                                

NOT: Bu işlemi FS modülündeki Dir ile de yapabiliyoruz. Başka FSO işlemi yapacaksak (FolderExists kullanmak gibi) bu yöntemi kullanalım, yoksa Dir yöntemini.

Klasör İçindeki Dosyaları Elde Etme

Bu işlem için Files property'si kullanılır. Folder'da olduğu gibi bir Collection elde eder ve ForEach uygularız:

                    
                            Sub KlasördekiDosyalar()
                                Dim anaklasorStr As String
                                Dim fol As Folder
                                Dim f As File

                                anaklasorStr = "C:\Users\Volkan\OneDrive\Dökümanlar"
                                Set fol = fso.GetFolder(anaklasorStr)

                                For Each f In fol.Files
                                    Debug.Print f.Name
                                    'diğer fso işlemleri
                                Next
                            End Sub
                                
                                

NOT: Bu işlemi FS modülündeki Dir ile de yapabiliyoruz. Başka FSO işlemi yapacaksak (FolderExists kullanmak gibi) bu yöntemi kullanalım, yoksa Dir yöntemini.

Klasör İçindeki (Tüm Alt Klasörlerin İçindekiler Dahil) Dosyaları Elde Etme

Bu örnek üsttekilere göre biraz daha karmaşıklık içerir ancak mantığı açısından güzel bir örnektir.

Alt klasörleri işleme dahil etmek için Collection tipinde bir yığın oluşturuyoruz ve her defasında bu yığının ilk üyesi üzerinde işlem yapıyoruz. İşlem yapmadan önce bu ilk elemanı yığından dışarı atıyoruz ki bir daha işleme girmesin. Sonra yığındaki elemanların (klasörlerin) her biri için işlemi yineliyoruz. Bu işlemi anlamanın en iyi yolu, Local penceresi açıkken F8 ile ilerlemek olacaktır.

NOT: Bunun daha hızlı ve basit yolu aşağıda Dir bölümünde ele alınacaktır. Ancak FSO nesnesiyle ilgili başka kontroller veya işlemler yapılması gerekirse bu yöntemin kullanılması tercih edilmelidir. Bu arada internette araştırırsanız başka yöntemler olduğunu da görebilirsiniz. Kullanım tercihi size kalmış.

Bu örnekte bir klasördeki dosyaların adını, bulunduğu klasörü ve dosya boyutunu yazdırıyoruz. Kendi diskinizdeki bir klasör ile yer değiştirerek deneyebilirsiniz:

                    
                    Sub KlasördekiAltKlasörDahilDosyalar()
                            Dim kls As Scripting.Folder, altkls As Scripting.Folder
                            Dim dosya As File
                            Dim klasörYığını As New Collection
                            Dim i As Integer
                            Dim YığındaNeVar As String, sabtiStr As String
                            Dim adım As Integer

                            klasörYığını.Add fso.GetFolder("C:\Users\Volkan\Videos\Movavi Screen Capture Studio\Udemy Kurslar\2-ileri vba-makro\FSO Örnek")
                            sabitstr = "C:\Users\Volkan\Videos\Movavi Screen Capture Studio\Udemy Kurslar\2-ileri vba-makro\"
                            i = 1
                            adım = 1

                            'yığındaki eleman sayısı 0 olana kadar yani tüm alt klasörler bitene kadar devam edicez
                            Do While klasörYığını.Count > 0

                                Set kls = klasörYığını(1)
                                klasörYığını.Remove 1 'ilk klasörü yığından çıkarıyoruz

                                'alt klasörleri yığına ekliyoruz
                                For Each altkls In kls.SubFolders
                                    klasörYığını.Add altkls
                                Next altkls

                                'bu if bloğu informativedir, silinebilir
                                If klasörYığını.Count > 0 Then
                                    For Each k In klasörYığını
                                        YığındaNeVar = Replace(k, sabitstr, "") & ";" & Replace(YığındaNeVar, sabitstr, "")
                                    Next k
                                    ActiveCell(i, 1).Value = Mid(YığındaNeVar, 1, Len(YığındaNeVar) - 1)
                                End If

                                For Each dosya In kls.files
                                    ActiveCell(i, 2).Value = adım & ". adımdaki klasör:" & kls.Name 'informativedir, silinebilir
                                    ActiveCell(i, 2).Offset(0, 1).Value = Replace(dosya.ParentFolder, sabitstr, "")
                                    ActiveCell(i, 2).Offset(0, 2).Value = dosya.Name
                                    ActiveCell(i, 2).Offset(0, 3).Value = dosya.Size
                                    i = i + 1
                                Next dosya
                                YığındaNeVar = vbNullString
                                adım = adım + 1
                            Loop
                        End Sub

                                
                            

Bu işlemi yapmanın bir diğer yolu da işlemi recursive bir şekilde ele almaktır.

                    
                    'ana prosedür
                        Sub recursive_fulldosya()
                            Dim anaklasorStr As String
                            anaklasorStr = "C:\inetpub\wwwroot\aspnettest\excelefendi2\"
                            Recursiveİlerle fso.GetFolder(anaklasorStr)
                        End Sub

                        'recursive prosedür
                        Sub Recursiveİlerle(kls As Variant) 'variant çünkü ilk girereken Folder sonra Folders olacak
                            Dim altKlasorler As Variant
                            Dim dosya As file
                            Static i As Integer ' her defasında bir önceki değerini koruması için

                            On Error Resume Next 'erişim izni olmayan yerlerde hata almasın diye
                            For Each altKlasorler In kls.SubFolders
                            Debug.Print altKlasorler 'bilgi amaçlıdır
                                Recursiveİlerle altKlasorler
                            Next

                            For Each dosya In kls.Files
                                ActiveCell(i, 1).Value = dosya.ParentFolder
                                ActiveCell(i, 1).Offset(0, 1).Value = dosya.Name
                                ActiveCell(i, 1).Offset(0, 2).Value = dosya.Size
                                i = i + 1
                            Next
                        End Sub

                                
                            
Diğer FSO ve File/Folder İşlemleri
Dosyaları ReadOnly Yapmak

Bu işlemi de FS modülü ile yapabiliyoruz. Neden böyle bir işlemi yapmak isteyeceğimi orada açıklıyorum. Burada sadece kısaca bu işlemin nasıl yapıldığına bakalım. Önceki örneklerde olduğu gibi eğer File nesnesi ile FileSystem ile yapılamayacak başka işlemler yapacaksanız bu yöntemi kullanın, yoksa en hızlısı FileSystem olduğu için onu kullanın.

                    
                        dosyaStr = "C:\deneme.xlsx"
                        Set dosya = fso.GetFile(dosyaStr)
                        dosya.Attributes = 1 'bu özellik hem okunur hem yazılırdır
                            
                            
Silme İşlemi

Yine FS ile de yapılabilir ve öncekilerde olduğu gibi FS'nin Kill fonksiyonunu kullanmak FSO'nun metodlarından daha efektiftir, özellikle büyük çaplı işlemlerde.

Bazı eylemler için FSO'nun metodlarını da File/Folder'ın metodlarını da kullanabiliyoruz, FS'nin fonksiyonlarını da. Tıpkı silme işleminde olduğu gibi. Aşağıdaki örnekte bu 3 yönteme de bakalım:

                    
                        Sub silmeler()
                        Dim f As file

                        '1.yöntem:Filesystem modülündeki Kill fonk ile
                        a = "C:\Users\Volkan\Desktop\a.txt"
                        FileSystem.Kill a 'FileSystem yazmaya gerek yoktur

                        '2.yöntem:fso nesnesi ile. Fso'yu başka amaçla da kullancaksak
                        b = "C:\Users\Volkan\Desktop\b.txt"
                        If fso.FileExists(b) Then
                            fso.DeleteFile b
                        End If

                        '3.yöntem:file nesnesi ile. File bilgisi lazımsa
                        c = "C:\Users\Volkan\Desktop\c.txt"
                        Set f = fso.GetFile(c)
                        If f.Size > 1024 Then
                            f.Delete
                        End If

                        End Sub
                            
                            
Kopyalama

Tek dosya kopyalamak

Kaynak olarak her zaman dosya adı belirtilir. Hedef olarak klasör adı veya dosya adı belirtilebilir (fso.CopyFile kaynakdosya, hedefklasör).

                    
                        'hedef: klasör
                        fso.CopyFile "C:\Users\Volkan\Desktop\denemeler\Şubeliste.xlsx", "C:\Users\Volkan\Desktop\ıvır zıvır\" 'sonda \ olmalı
                        'hedef: dosya adı, dosyanın adı değiştirilebilir
                        fso.CopyFile "C:\Users\Volkan\Desktop\denemeler\Şubeliste.xlsx", "C:\Users\Volkan\Desktop\ıvır zıvır\ŞubelisteforBölgeler.xlsx"
                            
                            
Aynı Tipteki Çoklu Dosya Kopyalama

Aşağıdaki kod ile kaynak klasördeki tüm xlsx, xlsm, xlsb, xls uzantılı dosyaları hedef klasöre kopyalamış oluyoruz:

                    
                        kaynak = "C:\Users\Volkan\Desktop\denemeler"
                        hedef = "C:\Users\Volkan\Desktop\ıvır zıvır\"

                        fso.CopyFile kaynak & "\*.xl*", hedef
                            
                            
Yeniden Adlandırmak ve Taşımak

MoveFile kullanılabileceği gibi MSDN'de dokumente edilmemiş bir Name fonksiyonu var bu da kullanılabilir. MoveFile kullanımı CopyFile'a benzer.

                    
                                Sub rename()

                                'kaynak dosya ve hedef klasör belirterek
                                fso.MoveFile "C:\Users\Volkan\Desktop\denemeler\Şubeliste.xlsx", "C:\Users\Volkan\Desktop\ıvır zıvır\" 'sonda "\" olmalı
                                'veya kaynak dosya, hedef dosya adı(farklı isim olabilir)
                                fso.MoveFile "C:\Users\Volkan\Desktop\denemeler\Şubeliste.xlsx", "C:\Users\Volkan\Desktop\ıvır zıvır\ŞubelisteforBölgeler.xlsx"
                                'veya
                                Name "C:\Users\Volkan\Desktop\denemeler\Şubeliste.xlsx" As "C:\Users\Volkan\Desktop\ıvır zıvır\ŞubelisteforBölgeler.xlsx"

                                End Sub
                                    
                                    
Dosya Son Değişim Tarihi Hakkında Bilgi Almak

Bir dosyanın gün içinde birkaç kez açılma durumu varsa ve dosyada bir kaydetme işlemi uygulanıyorsa, dosyanın daha önce kaydedilip edilmediği bilgisine bakarak sonraki açılışlarda kodun çalışmamasını sağlayabilirsiniz (veya tamamen başka sebeplerle).

                    
                            Set f = fso.GetFile(gunlukyol & adres)

                            If DateValue(f.DateLastModified) = Date Then
                               Exit Sub
                            Else
                               'diğer kodlar
                            End If
                                
                                
Dosya İsim, Uzantı ve Adresleri

Dosya isim, uzantı ve adreslerine sıklıkla ihtiyaç duyuyor olacağız. Bunların açıklamasını doğrudan kod içinde vermek daha kolay olacaktır.

                    
                            Sub cesitli_fsofilefolder()
                                Dim f As file
                                Dim k As Folder
                                dosya = "C:\Users\Volkan\Desktop\denemeler\deneme.xlsx"

                                Debug.Print fso.GetAbsolutePathName(dosya) 'C:\Users\Volkan\Desktop\denemeler\deneme.xlsx
                                Debug.Print fso.GetBaseName(dosya) 'deneme
                                Debug.Print fso.GetDriveName(dosya) 'C:
                                Debug.Print fso.GetExtensionName(dosya) 'xlsx
                                Debug.Print fso.GetFileName(dosya) 'deneme.xlsx
                                Debug.Print fso.GetParentFolderName(dosya) 'C:\Users\Volkan\Desktop\denemeler

                                Set f = fso.GetFile(dosya)

                                Debug.Print f.Name 'deneme.xlsx
                                Debug.Print f.ParentFolder 'denemeler
                                Debug.Print f.Path 'C:\Users\Volkan\Desktop\denemeler\deneme.xlsx
                                Debug.Print f.ShortName 'DENEME~1.XLS
                                Debug.Print f.ShortPath 'C:\Users\Volkan\Desktop\DENEME~1\DENEME~1.XLS

                                Set k = f.ParentFolder

                                Debug.Print k.Name 'denemeler
                                Debug.Print k.ParentFolder 'C:\Users\Volkan\Desktop
                                Debug.Print k.Path 'C:\Users\Volkan\Desktop\denemeler
                                Debug.Print k.ShortName 'DENEME~1
                                Debug.Print k.ShortPath 'C:\Users\Volkan\Desktop\DENEME~1

                            End Sub
                                
                                
FS Modülü

Yukarıda belirttiğimiz gibi FS modülü, class modül olmayıp bunun içindeki fonksiyonları kullanmak için bir FS nesnesi yaratmaya gerek bulunmamaktadır, daha da önemlisi FSO gibi başka bir library'yi reference olarak göstermeye gerek yoktur.

Yine yukarıda belirttiğimiz gibi FSO ve FS'nin ortak üyeleri bulunmaktadır. Amacımız sadece bu metodu kullanmak ise tercih her zaman FS'den yana olmalı, ancak FSO'nun diğer üyeleriyle de işlem yapılacaksa işte o zaman FSO kullanılmalıdır.

FS'nin Metodları

Şimdi FS'nin metdolarına bakalım.

Dir

Dir heralde FS'nin en önemli fonksiyonudur. Parametre olarak dosya/klasör adı alır. Bunu kullanırken bir klasörle işlem yapacaksak en sonda hep "\" olmasına dikkat edilmelidir. Zira bu fonksiyoni aldığı parametrenin dosya mı klasör mü olduğunu sondaki "\" ile anlıyor. O yüzden Dir ile ilgili işlem yapmadan önce sağ tarafa "\" olup olmadığına göre aşağıdaki gibi bi düzeltme işlemi yapılmasında fayda var.(tabi bir klasör ile uğraştığımızı düşünüyorsak)

                    
                            If Right(klasor, 1) <> "\" Then
                                klasor = klasor & "\"
                            End If
                                
                                

Bu fonksiyonün dönüş değeri String'tir. Peki ne döndürür?

  • Parametre olarak Klasör adresi alıyorsa, klasördeki ilk dosyanın adını
  • Parametre olarak Dosya adresi alıyorsa, dosyanın kendisini
  • Parametre olark ne alırsa alsın, eğer böyle bir dosya/klasör yoksa ZLS, yani sıfır uzunluklu bir metin döndürür
                    
                                Sub fs_dir()

                                kls1 = "C:\Users\Volkan\Desktop\denemeler" 'sonunda \ yok
                                kls2 = "C:\Users\Volkan\Desktop\denemeler\"
                                dsy = "C:\Users\Volkan\Desktop\denemeler\algo.xlsx"

                                Debug.Print Dir(kls1) 'hiçbişrey döndürmez
                                Debug.Print Dir(kls2) 'klasördeki ilk dosyayı döndürür
                                Debug.Print Dir(dsy) 'dosyanın kendisini döndürür

                                Debug.Print Len(Dir("var_olmayan_dosya_veya_klasör"))

                                End Sub
                                    
                                    

Bu fonksiyon FSO'nun FileExists/FolderExists özellikleri yerine de kullanılabilir ancak bunlardan farklı olarak True/False döndürmez, yukarıda belirttiğimiz gibi bir string döndürür, ilgili parametreyi bulamazsa ZLS döndürür demiştik. O yüzden sonucun vbNullString olup olmadığına bakmalıyız.

Var mı? kontrolü
                    
                            Sub kontrol2()

                            If Dir("C:\Users\Volkan\Desktop\denemeler\deneme.xlsx") <> vbNullString Then
                                Debug.Print "Dosya var"
                            End If

                            If Dir("C:\Users\Volkan\Desktop\denemeler\") <> vbNullString Then 'sondaki \ işaretine dikkat. Bu klasör mevcut olsa bile \ işareti olmazsa Null döndürür
                                Debug.Print "Klasör var"
                            End If

                            End Sub
                                
                                

Aşağıda Excel gurularından Ken Puls tarafından bir fonksiyon haline dönüştürülmüş(benim de bir zamanlar sıklıkla kullandığım) versiyonunu görüyorsunuz.

                    
                            Public Function FileFolderExists(strFullPath As String) As Boolean
                            'Author       : Ken Puls (www.excelguru.ca)
                            'Macro Purpose: Check if a file or folder exists

                                If strFullPath = vbNullString Then Exit Function
                                On Error GoTo EarlyExit
                                If Not Dir(strFullPath, vbDirectory) = vbNullString Then FileFolderExists = True

                            EarlyExit:
                                On Error GoTo 0
                            End Function
                                
                                

Kullanımı

                    
                        Sub varmı_test()
                            'adres olarak dosya adresi de klasör adresi de verilebilir
                            Const adres As String = "var_olmayan_dosya_veya_klasör"
                            If FileFolderExists(adres) Then
                                Debug.Print "var"
                            Else
                                Debug.Print "yok"
                            End If
                        End Sub
                            
                            
Mevcutmu Fonksiyonu

Bu tür şeylerin üzerine kafa yorunca daha basit çözümler bulabiliyorsunuz. Mesela ben aşağıdaki çözümü buldum. Yaptığım şey basit: Parametre olarak verilen şeyin hem file hem folder için işleyen GetAttr metodu ile attribute bilgisini almaya çalışıyorum; eğer bilgi alabilirsem demek ki dosya veya klasör mevcuttur; bilgi alamıyorsam, ki öyleyse hata üretir, o zaman hata yönetim bloğu ile de fonksiyona False değerini atarım.

                    
                                Function Mevcutmu(adres As String) As Boolean
                                On Error GoTo hata
                                If GetAttr(adres) >= 0 Then Mevcutmu = True
                                Exit Function

                                hata:
                                Mevcutmu = False
                                End Function

                                'kullanım
                                Sub mevcutmu_test()
                                Debug.Print Mevcutmu("C:\Users\Volkan\") 'True
                                Debug.Print Mevcutmu("C:\Users\Volki\") 'False
                                Debug.Print Mevcutmu("C:\Users\Volkan\Desktop\denemeler\deneme.xlsx") 'True
                                Debug.Print Mevcutmu("C:\Users\Volkan\Desktop\denemeler\deneme5.xlsx") 'false
                                End Sub
                                    
                                    
İkinci Parametre

Dir'in ikinci parametresi çeşitli constantları alır, bunların en önemlisi vbDirectory'dir. İkinci parametre girilmezse (veya vbNormal olarak girilirse, ki default olanı budur) ilk dosyayı elde ederiz demiştik, işte bu ikinci parametre vbDirectory olarak girilirse klasörün kendisini elde ederiz, ve bunu "." olarak görürüz.

Aşağıdaki klasör göz önüne alındığında;

post-thumb
                    
                                    Sub dir_ikinciparametre()

                                    Debug.Print Dir("C:\Users\Volkan\Desktop\denemeler\")  'klasördeki ilk dosyayı verir, ALGORİTMA.xlsx
                                    Debug.Print Dir("C:\Users\Volkan\Desktop\denemeler\ALGORİTMA.xlsx")  'dosyanını kendisini verir
                                    Debug.Print Dir("C:\Users\Volkan\Desktop\denemeler\", vbDirectory)  'Klasörün kendisi yani '.'
                                    Debug.Print Dir("C:\Users\Volkan\Desktop\denemeler\ALGORİTMA.xlsx", vbDirectory) 'dosyanını kendisini verir

                                    End Sub
                                        
                                        
Çoklu Kullanım

Dir'in iki parametresi de opsiyonel olmakla birlikte, ilk kullanımı mutlaka parametreli olmalıdır. Ondan sonra hiç parametre almadan da kullanılabilir. Parametresiz kullanım, "sonraki dosya/klasöre geç" demektir.

Dir'i bu şekilde arka arkaya kullandığımızda bi yerde artık sona ulaşılır ve yeni bir dosya/klasör elde edilemez; işte bu noktada sonuç ZLS'dir. O yüzden bu noktaya ulaşıldığında ya bu tekrarlı çağırma işini sonlandırmalı, ki bu genelde bi döngü içinde yapıldığından döngüdnen çıkmak anlamına gelir, ya da yeniden parametreli bir kullanıma geçmelisiniz.

                    
                                    Sub çok_kullanım()

                                    Debug.Print Dir("C:\Users\Volkan\Desktop\denemeler\")
                                    Debug.Print Dir 'parantezsiz de kullanılabilir
                                    Debug.Print Dir() 'parantezli de 
                                    Debug.Print Dir("") 'klasördeki ilk dosyaya döner

                                    Debug.Print Dir("C:\Users\Volkan\Desktop\denemeler\ALGORİTMA.xlsx")
                                    Debug.Print Dir 'Dosyalarda bu ZLS döndürür
                                    'Debug.Print Dir() 'Bu hata verir
                                    Debug.Print Dir("") 'klasördeki ilk dosyaya döner

                                    End Sub
                                        
                                        
Klasör İçindeki Klasörleri Elde Etme

Bu işlemi FSO altında da incelemiştik. Ancak eğer FSO ile ilgili başka bir işlem yapılmayacaksa Dir ile çok daha hızlı yapılır. (Koddaki GetAttr'le ilgili satıra çok takılmayın, bunu şimdilik ezbere kullanın, zira konu biraz karışık, merak edenler için burada detaylı açıklama var.)

                    
                            Sub LoopinKlasör()
                            Dim i As Integer
                            i = 1

                            anaklasor = "C:\inetpub\wwwroot\aspnettest\excelefendi2\"
                            klasor = Dir(anaklasor, vbDirectory)   'kendisini alarak başlıyoru

                            Do Until klasor = ""   'Dir'den klasor dönmeyene kadar ilerliyoruz
                              If (GetAttr(anaklasor & klasor) And vbDirectory) = vbDirectory Then
                                ActiveSheet.Cells(i, 1).Value = anaklasor & klasor
                                i = i + 1
                              End If
                              klasor = Dir()   'Parametresiz dir ile sonraki klasöre ilerliyoruz(dosyalarla çalışsaydık sonraki dosya)
                            Loop
                            End Sub
                                
                                

NOT: Bu döngü sırasında görünen "..", parent klasörü temsil eder.

Klasör İçindeki Dosyaları Elde Etme

Yine bu işlem de FSO ile yapılabilmekteydi ancak FSO'nun başka kullanımı olmayacaksa Dir ile yapmak daha hızlıdır.

İlk parametreli Dir'den sonraki parametresiz Dir ile aynı klasörde ilerleriz. Ayrıca Dir, joker eleman da aldığı için tüm dosyalarda değil belli dosyalar üzerinde de dolaşabilirsiniz.

Aşağıdaki örneklerde, bir klasörde "vba" ifadesi içeren dosya isimlerini yazdırıyoruz. 350 dosya içeren bu klasörde Dir'in çalışma hızı 0,17 sn iken FSO 0,53 sn olmuştur. Daha kalabalık klasörlerde fark daha da açılmaktadır.

                    
                        'Dir ile
                        Sub dosyalarda_gezin_dir()
                            Dim bas As Single, bts As Single
                            bas = Timer
                            f = Dir("C:\Users\Volkan\Desktop\denemeler\*al*") 'içinde "al" geçen ilk dosyayı bulur
                            Debug.Print f
                            Do While Len(f) > 0
                                f = Dir 'sonraki dosyaya geçiyoruz. Sonunda () gerekli değil, olsa da olur olmasa da
                                Debug.Print f
                            Loop
                            bts = Timer
                            Debug.Print bts - bas
                        End Sub

                        'FSO ile daha uzun
                        Sub dosyalarda_gezin_fsofilefolder()
                           Dim bas As Single, bts As Single

                           Dim fso As New FileSystemObject
                           Dim kaynak As Scripting.Folder
                           Dim dosya As File

                           bas = Timer
                           Set kaynak = fso.GetFolder("C:\Users\Volkan\Desktop\denemeler\")
                           For Each dosya In kaynak.files
                              If InStr(dosya.Name, "al") > 0 Then
                                    Debug.Print dosya.Name
                              End If
                           Next dosya
                           bts = Timer
                           Debug.Print bts - bas
                        End Sub
                            
                            
Klasör İçindeki (Tüm Alt Klasörler Dahil) Dosyaları Elde Etme

Yine aynı açıklamamız geçerli. FSO ile de yapabiliriz, ancak Dir daha hızlıdır. Eğer ki FSO'yu başka amaçla da kullanacaksak FSO tercih edilmeli, yoksa Dir.

Aşağıdaki örneği şuradan aldım. Kendi ihtiyacınıza göre değiştirebilirsiniz. F8 ve Local Windows aracılığı ile değişiklikleri izleyerek incelemenizi tavsiye ederim.

                    
                            Sub recursive_Dir()
                                 Dim colFiles As New Collection
                                 RecursiveDir colFiles, "C:\deneme", "*.*", True
                                 Dim vFile As Variant
                                 For Each vFile In colFiles
                                     Debug.Print vFile
                                 Next vFile
                            End Sub

                            'recursive Fonksiyonumuz    
                            Public Function RecursiveDir(colFiles As Collection, _
                                                          strFolder As String, _
                                                          strFileSpec As String, _
                                                          bIncludeSubfolders As Boolean)
                                 Dim strTemp As String
                                 Dim colFolders As New Collection
                                 Dim vFolderName As Variant
                                 'Add files in strFolder matching strFileSpec to colFiles
                                 strFolder = TrailingSlash(strFolder)
                                 strTemp = Dir(strFolder & strFileSpec)
                                 Do While strTemp <> vbNullString
                                     colFiles.Add strFolder & strTemp
                                     strTemp = Dir
                                 Loop
                                 If bIncludeSubfolders Then
                                     'Fill colFolders with list of subdirectories of strFolder
                                     strTemp = Dir(strFolder, vbDirectory)
                                     Do While strTemp <> vbNullString
                                         If (strTemp <> ".") And (strTemp <> "..") Then
                                             If (GetAttr(strFolder & strTemp) And vbDirectory) <> 0 Then
                                                 colFolders.Add strTemp
                                             End If
                                         End If
                                         strTemp = Dir
                                     Loop
                                     'Call RecursiveDir for each subfolder in colFolders
                                     For Each vFolderName In colFolders
                                         Call RecursiveDir(colFiles, strFolder & vFolderName, strFileSpec, True)
                                     Next vFolderName
                                 End If
                            End Function

                            'Dir kullanırken sondaki \ işareti önemli olduğu için bunu ele alma fonksiyonu
                            Public Function TrailingSlash(strFolder As String) As String
                                 If Len(strFolder) > 0 Then
                                     If Right(strFolder, 1) = "\" Then
                                         TrailingSlash = strFolder
                                     Else
                                         TrailingSlash = strFolder & "\"
                                     End If
                                 End If
                            End Function
                                
                                
Klasör İçindeki Dosyaları Elde Etme

Yine bu işlem de FSO ile yapılabilmekteydi ancak FSO'nun başka kullanımı olmayacaksa Dir ile yapmak daha hızlıdır.

İlk parametreli Dir'den sonraki parametresiz Dir ile aynı klasörde ilerleriz. Ayrıca Dir, joker eleman da aldığı için tüm dosyalarda değil belli dosyalar üzerinde de dolaşabilirsiniz.

Aşağıdaki örneklerde, bir klasörde "vba" ifadesi içeren dosya isimlerini yazdırıyoruz. 350 dosya içeren bu klasörde Dir'in çalışma hızı 0,17 sn iken FSO 0,53 sn olmuştur. Daha kalabalık klasörlerde fark daha da açılmaktadır.

                    
                                'Dir ile
                                Sub dosyalarda_gezin_dir()
                                    Dim bas As Single, bts As Single
                                    bas = Timer
                                    f = Dir("C:\Users\Volkan\Desktop\denemeler\*al*") 'içinde "al" geçen ilk dosyayı bulur
                                    Debug.Print f
                                    Do While Len(f) > 0
                                        f = Dir 'sonraki dosyaya geçiyoruz. Sonunda () gerekli değil, olsa da olur olmasa da
                                        Debug.Print f
                                    Loop
                                    bts = Timer
                                    Debug.Print bts - bas
                                End Sub

                                'FSO ile daha uzun
                                Sub dosyalarda_gezin_fsofilefolder()
                                   Dim bas As Single, bts As Single

                                   Dim fso As New FileSystemObject
                                   Dim kaynak As Scripting.Folder
                                   Dim dosya As File

                                   bas = Timer
                                   Set kaynak = fso.GetFolder("C:\Users\Volkan\Desktop\denemeler\")
                                   For Each dosya In kaynak.files
                                      If InStr(dosya.Name, "al") > 0 Then
                                            Debug.Print dosya.Name
                                      End If
                                   Next dosya
                                   bts = Timer
                                   Debug.Print bts - bas
                                End Sub
                                    
                                    
Klasör İçindeki (Tüm Alt Klasörler Dahil) Dosyaları Elde Etme

Yine aynı açıklamamız geçerli. FSO ile de yapabiliriz, ancak Dir daha hızlıdır. Eğer ki FSO'yu başka amaçla da kullanacaksak FSO tercih edilmeli, yoksa Dir.

Aşağıdaki örneği şuradan aldım. Kendi ihtiyacınıza göre değiştirebilirsiniz. F8 ve Local Windows aracılığı ile değişiklikleri izleyerek incelemenizi tavsiye ederim.

                    
                            Sub recursive_Dir()
                                 Dim colFiles As New Collection
                                 RecursiveDir colFiles, "C:\deneme", "*.*", True
                                 Dim vFile As Variant
                                 For Each vFile In colFiles
                                     Debug.Print vFile
                                 Next vFile
                            End Sub

                            'recursive Fonksiyonumuz    
                            Public Function RecursiveDir(colFiles As Collection, _
                                                          strFolder As String, _
                                                          strFileSpec As String, _
                                                          bIncludeSubfolders As Boolean)
                                 Dim strTemp As String
                                 Dim colFolders As New Collection
                                 Dim vFolderName As Variant
                                 'Add files in strFolder matching strFileSpec to colFiles
                                 strFolder = TrailingSlash(strFolder)
                                 strTemp = Dir(strFolder & strFileSpec)
                                 Do While strTemp <> vbNullString
                                     colFiles.Add strFolder & strTemp
                                     strTemp = Dir
                                 Loop
                                 If bIncludeSubfolders Then
                                     'Fill colFolders with list of subdirectories of strFolder
                                     strTemp = Dir(strFolder, vbDirectory)
                                     Do While strTemp <> vbNullString
                                         If (strTemp <> ".") And (strTemp <> "..") Then
                                             If (GetAttr(strFolder & strTemp) And vbDirectory) <> 0 Then
                                                 colFolders.Add strTemp
                                             End If
                                         End If
                                         strTemp = Dir
                                     Loop
                                     'Call RecursiveDir for each subfolder in colFolders
                                     For Each vFolderName In colFolders
                                         Call RecursiveDir(colFiles, strFolder & vFolderName, strFileSpec, True)
                                     Next vFolderName
                                 End If
                            End Function

                            'Dir kullanırken sondaki \ işareti önemli olduğu için bunu ele alma fonksiyonu
                            Public Function TrailingSlash(strFolder As String) As String
                                 If Len(strFolder) > 0 Then
                                     If Right(strFolder, 1) = "\" Then
                                         TrailingSlash = strFolder
                                     Else
                                         TrailingSlash = strFolder & "\"
                                     End If
                                 End If
                            End Function