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).
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:
Outlook Klasörü olan Folder'ın üyeleri böyledir:
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;
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