Dosya okuma ve yazma

İçine veri yazılan birçok dosya tipi bulunmaktadır, ancak biz VBA konsepti içinde genellikle text(csv dahil) dosyalarıyla çalışacağız. SQL kodlarını depoladığınız ".sql" uzantılı dosyaları da bu kapsamda düşünebilirsiniz. Excel dosyalarla çalışmayı zaten Workbook ve Application bölümlerinde görmüştük.
Text dosyaları bilgi depolayıp okumanın kolay bir yolunu sunarlar. Özellikle settings(ayar) bilgileri veya aşamalı bir sürecin durum bilgilerini(log) okumakta/yazmakta oldukça kullanışlıdırlar.
VBA'de iki tür okuma/yazma yöntemi bulunuyor. Öncelikle biz VB6'dan miras gelen klasik okuma yazma yöntemine bakacağız.
UYARI:Buradan itibaren aşağıda göreceğiniz tüm dosya okuma işlemlerinde, dosya okuma hep sağa ve aşağı yönlüdür. Döngüsel işlemlerde "bir sağ kolona/karaktere veya bir alt satıra geç" tarzında ilave bir kod ifadesi yoktur. Bu işlem otomatik olmaktadır.

Dosya Açma ve Kapama
Dosya Açma

Okuma işlemi için de yazma işlemi için de öncelikle dosyanın açılması gerekir. Bunun için Open fonksiyonu kullanılır. Aşağıdaki gibi bir syntax'a sahiptir:

Open dosyayolu For mod [Erişim tipi] [lock] As Dosyano

  • Dosyayolu: Dosyanın bulunduğu tam adres. Ör: C:\deneme\deneme.txt
  • Mod: Input ise okuma, Output ise yazma, Append ise dosya sonuna ekleme yapılır. 2 tane daha var ama bize bu üçü yeter. Output seçildiğinde mevcut dosya varsa ezilip içeriği yeniden oluşturulur, olmayan bir dosya girildiyse bu dosya yaratılır.
  • Erişim tipi ve Lock tipi: Opsiyoneldirler. Dosya açıkken, başkalarının ne yapabileceğini gösterir. Biz bunları kullanmayacağız, o yüzden default değerleri devreye girecek.
Freefile

Dosyalar açıldığında onlara bir sıra numarası verilir. Bu numara manuel belirtilebileceği gibi, çok sayıda okuma yazma yapılan bir prosedür içinde o andaki müsait sıra numarasını veren Freefile deyimi de kullanılabilir. Manuel giriş için sıra numarası # ile kullanılır. #1 gibi.

Dosyayı Kapama

Dosyayı Close ifadesi ile kaparız, ancak parametre olarak dosya adresi değil, numarasını alır.

Dosyayı kapatmazsak, tekrar aynı dosyayı açmaya çalıştığımızda "Dosya zaten açık" hatası alırız.

Kod

Bu durumda, örnek bir dosya açma kodu aşağıdaki gibi olacaktır:

                    
                            adres = "C:\Users\Volkan\Desktop\denemeler\dosya1.txt"
                            Open adres For Input As #1 'veya 1 veya FreeFile
                            'çeşitli işlemler

                            Close #1
                                
                                
Dosyadan Veri Okuma
Kolon Kolon Bilgi Okumak

Aşağıdaki bilgileri içeren bir text dosyamız olsun. Kişinin adı, yaşı ve baba adı bilgileri var:

volkan ,38 ,ismail
ayşe ,40 ,murat
serkan ,35 ,osman

Buradan ilk kaydın yaş bilgisini almak istiyoruz diyelim. Bunun için Input deyimini kullanıp, istediğimiz kolon sayısı kadar değişken belirleyip kolon bilgilerini bu değişkenlere atıyoruz.

                    
                        Sub teksatırdan_tekkolon_okuma()
                        adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                        Open adres For Input As 1
                        Input #1, adı, yaş 'kolon sayısı kadar parametre alır. # zorunlu
                        Debug.Print yaş '38 verir
                        'ikinci bir Debug.Print yaş yazsak bile yine 38 yazar. sadece tek satır okuması var.
                        Close 1

                        End Sub
                            
                            

Bu kod tabii ki sadece ilk satır için bilgi döndürür. Satırda ilerleme yapamıyoruz. Özellikle her defasında üzerine yazma yapılan tek satırlık bilgi içeren dosyalarda kullanışlıdır. Mesela ikinci kolonunda, bilginin yazdırıldığı tarihi veya kişiyi gösteren bir dosyadan bu tarihi veya kişiyi elde etmek isteyebiliriz. Böylece bu dosyaya en son ne zaman bilgi yazıldığını veya kimin tarafından yazıldığını elde edebiliriz.

Tek Satırdan Kısmi Bilgi Okuma

Input ifadesini Input(karakteradedi, dosyano) şeklinde kullandığımızda belirli adette karakter okumuş oluruz.

                    
                        Sub teksatır_kısmen_okuma()
                        adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                        Open adres For Input As 1
                        x = Input(6, 1) '1 nolu dosyadan 6 karakter oku
                        Debug.Print x 'volkan
                        End Sub
                            
                            
İlk Satırın Tamamını Okuma

Yine yukarıdaki dosyamız elimizde bulunsun. Bu sefer ilk satırın tamamını elde edeceğiz. Bunu Line Input deyimi ile yapıyor ve içeriği ikinci parametredeki değişkene atıyoruz.

                    
                        Sub teksatır_tamamını_okuma()

                        adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                        Open adres For Input As 1 
                        Line Input #1, metin 'ilk satırı oku ve metin değişkeninde depola
                        Debug.Print metin 'volkan,38,ismail yazar

                        Close 1

                        End Sub
                            
                            
x Adet Satırı Tek Tek Okuma

Bu işlem Line Input'un bir For Next döngüsü ile kullanımı ile yapılabilir. Belli sayıda satır bilgisinin yeterli olduğu durumlarda kullanılır.

                    
                                Sub x_adet_satır_oku()

                                adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                                Open adres For Input As 1
                                For i = 1 To 2
                                  Line Input #1, metin
                                  Debug.Print metin
                                Next i

                                Close 1

                                End Sub
                                    
                                    
Dosyadaki Tüm Metni Okuma
1. Yöntem: Dosyadaki Karakter Sayısı Kadar Okumak

Bunu LOF ifadesi ile yapıyoruz. Bu, Length Of File'ın kısaltılmışıdır, yani dosyadaki karakter sayısını verir. Input ile birleştirerek de dosyadaki tüm karakter sayısını oku demiş oluruz. "volkan naber" şeklinde 12 karakterli bir metni içeren bir dosyada:

  • LOF(1): 12 döndürür
  • Input(LOF(1), 1): 1 nolu dosyayı tamamen okur: "volkan naber"

Örnek bir kodumuz ise şöyledir. Bu kodda ayrıca Seek ifadesini de kullandık. Bununla dosyada belirli bir sıradaki karaktere konumlanıyoruz, ki bunu genelde belirli bir sırayla ilerledikten sonra tekrar ilk karaktere dönmek için kullanırız. Syntax: Seek dosyano, konum

                    
                            Sub DosyaOkuTümü1()

                            adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"
                            Open adres For Input As 1

                            Debug.Print LOF(1) 'Length Of File Of File

                            içerik = Input(LOF(1), 1) '1 nolu dosyanın hepsini oku
                            Debug.Print içerik

                            Seek 1, 1 '1 nolu dosyanın 1. karakterine yani en başa git
                            içerik = Input(LOF(1) - 10, 1) '1 nolu dosyanın son 10 karakteri hariç oku
                            Debug.Print içerik

                            Seek 1, 5 '1 nolu dosyanın 5. karakterine git
                            içerik = Input(10, 1) '1 nolu dosyanın 5. karakterinden sonraki ilk 10 karakterini oku
                            Debug.Print içerik

                            Close 1

                            End Sub
                                
                                

Aynı mantıkla bir şekilde dosyanın ilk x karakterini okumak için içerik değişkenine Input(x, 1); son x karakteri hariç okuma yapmak isterseniz içerik değişkenine Input(LOF(1) - x, 1) şeklinde atama yaparsınız.

Bu yöntemde dosya içindeki metnin kaç satırda yer aldığı önemli değildir. Tüm metin tek bir değişkende depolanır.

2. Yöntem: Dosya Sonuna Kadar Satır Satır Okumak

Yukarıda gördüğümüz belli sayıdaki satırları tek tek okumadan farklı olarak tüm satırları tek tek okuyoruz. Satırların bittiğini EOF (End Of File'ın kısaltması) özelliği ile anlıyoruz.

                    
                                Sub DosyaOkuTümü2()
                                tamadres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                                Open tamadres For Input As 1

                                Line Input #1, satırmetni
                                içerik = satırmetni

                                Do Until EOF(1)
                                  Line Input #1, satırmetni
                                  içerik = içerik & vbNewLine & satırmetni
                                Loop

                                Debug.Print içerik

                                Close 1
                                End Sub
                                    
                                    

NOT: İçerik değişkenini oluştururken kayıtlar arasında vbNewLine koyarak satırbaşı yapıyoruz. Ancak ilk başta değişkenin içi boş olacağı için fazladan bir boş satır oluşmaması için en başta bir kezliğine döngüye girmeden ilk satırın atamasını yapıyorum, sonrasında döngü içinde vbNewLine ekliyorum.

Bu arada istenirse ilgili metinler vbNewLine denmeden satır satır değil de ardışık bir şekilde de bir araya getirilebilir.

Tüm İçeriği Bir Diziye Aktarmak

Bunu da kendi içinde iki ayrı yöntemle yapabiliriz. İlk yöntemde satır satır okur ve her satırı bir collection'a atarız. Özellikle her satırın başına/sonuna başka bir metin eklemek gereken durumlarda bunu kullanabiliriz. İkinci yöntemde ise tüm metni okuyup Enter'ları (vbCrLf veya vbNewLine) Split ederek diziye atayabilirsiniz.

                    
                    '1) Collection'a atama
                    Do Until EOF(1)
                      Line Input #1, metin
                      coll.Add metin
                    Loop

                    '2) Diziye atama
                    içerik = Input(LOF(1), 1)
                    dizi = Split(içerik, vbCrLf)
                        
                        

Bu iki yöntemle de yukarıdaki örneği yapalım.

                    
                            Sub dosyaoku3()

                            adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                            Open adres For Input As 1

                            Debug.Print "------önce dizi yöntemi-----"
                            içerik = Input(LOF(1), 1)
                            dizi = Split(içerik, vbCrLf)

                            For Each satır In dizi
                                Debug.Print "Prefix:" + satır + " -Suffix"
                            Next satır

                            'veya
                            Debug.Print "------collection yöntemi-----"
                            Seek 1, 1
                            Dim coll As New Collection
                            Do Until EOF(1)
                              Line Input #1, metin
                              coll.Add metin
                            Loop

                            For Each satır In coll
                                Debug.Print "Prefix:" + satır + " -Suffix"
                            Next satır

                            Close 1

                            End Sub
                                
                                
Virgülle Ayrılmış Metinleri Hücrelere Yazdırmak

Virgülle ayrılmış tüm değerleri farklı kolonda olacak şekilde satır satır Excel'e yazdırmak isteyebilirsiniz. Bunun için satır satır okuma yapmamız gerekir ve her satırı Split ile bir diziye atayabilir, sonra da ilgili hücrelere bu dizi elemanlarını döngüsel şekilde yazdırabiliriz.

Dosyadaki Tüm Metni Okuma
1. Yöntem: Dosyadaki Karakter Sayısı Kadar Okumak

Bunu LOF ifadesi ile yapıyoruz. Bu, Length Of File'ın kısaltılmışıdır, yani dosyadaki karakter sayısını verir. Input ile birleştirerek de dosyadaki tüm karakter sayısını oku demiş oluruz. "volkan naber" şeklinde 12 karakterli bir metni içeren bir dosyada:

  • LOF(1): 12 döndürür
  • Input(LOF(1), 1): 1 nolu dosyayı tamamen okur: "volkan naber"

Örnek bir kodumuz ise şöyledir. Bu kodda ayrıca Seek ifadesini de kullandık. Bununla dosyada belirli bir sıradaki karaktere konumlanıyoruz, ki bunu genelde belirli bir sırayla ilerledikten sonra tekrar ilk karaktere dönmek için kullanırız. Syntax: Seek dosyano, konum

                    
                            Sub DosyaOkuTümü1()

                            adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"
                            Open adres For Input As 1

                            Debug.Print LOF(1) 'Length Of File Of File

                            içerik = Input(LOF(1), 1) '1 nolu dosyanın hepsini oku
                            Debug.Print içerik

                            Seek 1, 1 '1 nolu dosyanın 1. karakterine yani en başa git
                            içerik = Input(LOF(1) - 10, 1) '1 nolu dosyanın son 10 karakteri hariç oku
                            Debug.Print içerik

                            Seek 1, 5 '1 nolu dosyanın 5. karakterine git
                            içerik = Input(10, 1) '1 nolu dosyanın 5. karakterinden sonraki ilk 10 karakterini oku
                            Debug.Print içerik

                            Close 1

                            End Sub
                                
                                

Aynı mantıkla bir şekilde dosyanın ilk x karakterini okumak için içerik değişkenine Input(x, 1); son x karakteri hariç okuma yapmak isterseniz içerik değişkenine Input(LOF(1) - x, 1) şeklinde atama yaparsınız.

Bu yöntemde dosya içindeki metnin kaç satırda yer aldığı önemli değildir. Tüm metin tek bir değişkende depolanır.

2. Yöntem: Dosya Sonuna Kadar Satır Satır Okumak

Yukarıda gördüğümüz belli sayıdaki satırları tek tek okumadan farklı olarak tüm satırları tek tek okuyoruz. Satırların bittiğini EOF (End Of File'ın kısaltması) özelliği ile anlıyoruz.

                    
                            Sub DosyaOkuTümü2()
                            tamadres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                            Open tamadres For Input As 1

                            Line Input #1, satırmetni
                            içerik = satırmetni

                            Do Until EOF(1)
                              Line Input #1, satırmetni
                              içerik = içerik & vbNewLine & satırmetni
                            Loop

                            Debug.Print içerik

                            Close 1
                            End Sub
                                
                                

NOT: İçerik değişkenini oluştururken kayıtlar arasında vbNewLine koyarak satırbaşı yapıyoruz. Ancak ilk başta değişkenin içi boş olacağı için fazladan bir boş satır oluşmaması için en başta bir kezliğine döngüye girmeden ilk satırın atamasını yapıyorum, sonrasında döngü içinde vbNewLine ekliyorum.

Bu arada istenirse ilgili metinler vbNewLine denmeden satır satır değil de ardışık bir şekilde de bir araya getirilebilir.

Tüm İçeriği Bir Diziye Aktarmak

Bunu da kendi içinde iki ayrı yöntemle yapabiliriz. İlk yöntemde satır satır okur ve her satırı bir collection'a atarız. Özellikle her satırın başına/sonuna başka bir metin eklemek gereken durumlarda bunu kullanabiliriz. İkinci yöntemde ise tüm metni okuyup Enter'ları (vbCrLf veya vbNewLine) Split ederek diziye atayabilirsiniz.

                    
                    '1) Collection'a atama
                    Do Until EOF(1)
                      Line Input #1, metin
                      coll.Add metin
                    Loop

                    '2) Diziye atama
                    içerik = Input(LOF(1), 1)
                    dizi = Split(içerik, vbCrLf)
                        
                        

Bu iki yöntemle de yukarıdaki örneği yapalım.

                    
                        Sub dosyaoku3()

                        adres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                        Open adres For Input As 1

                        Debug.Print "------önce dizi yöntemi-----"
                        içerik = Input(LOF(1), 1)
                        dizi = Split(içerik, vbCrLf)

                        For Each satır In dizi
                            Debug.Print "Prefix:" + satır + " -Suffix"
                        Next satır

                        'veya
                        Debug.Print "------collection yöntemi-----"
                        Seek 1, 1
                        Dim coll As New Collection
                        Do Until EOF(1)
                          Line Input #1, metin
                          coll.Add metin
                        Loop

                        For Each satır In coll
                            Debug.Print "Prefix:" + satır + " -Suffix"
                        Next satır

                        Close 1

                        End Sub
                            
                            
Virgülle Ayrılmış Metinleri Hücrelere Yazdırmak

Virgülle ayrılmış tüm değerleri farklı kolonda olacak şekilde satır satır Excel'e yazdırmak isteyebilirsiniz. Bunun için satır satır okuma yapmamız gerekir ve her satırı Split ile bir diziye atayabilir, sonra da ilgili hücrelere bu dizi elemanlarını döngüsel şekilde yazdırabiliriz.

                    
                            Sub DosyaOkuTümü4()
                            tamadres = "C:\Users\volkan\Desktop\denemeler\dosya1.txt"

                            Open tamadres For Input As 1

                            i = i + 1
                            Do Until EOF(1)
                              Line Input #1, x
                              dizi = Split(x, ",")
                              For j = 0 To UBound(dizi)
                                Cells(i, j + 1) = dizi(j)
                              Next j
                              i = i + 1
                            Loop

                            Close 1
                            End Sub
                                
                                
Dosyaya Veri Yazma
Sıfırdan Yazma

Dosyaya veri yazdırmak için dosyayı Output modunda açmamız gerekir. Yazdırma eylemi için iki fonksiyonumuz var: Write ve Print. Write, yazdırılan ifadeyi " " içine alarak yazarken Print böyle bir işlem yapmaz.

Örenğin:

Dosyaya veri yazma

Sıfırdan yazma

Dosyaya veri yazdırmak için dosyayı Output modunda açmamız gerekir. Yazdırma eylemi için iki fonksiyonumuz var. Write ve Print. Write, yazdırılan ifadeyi " " içine alarak yazarken Print böyle bir işlem yapmaz.

Her iki deyim de ardışık kullanımlarında satır satır yazdırır. Yani birbirini takip eden metinler şeklinde yazılmaz. Örneğin;

                    
                        ad="Volkan"
                        soyad="Yurtseven"

                        Print ad
                        Print soyad

                        'bu kodun çıktısı aşağıdaki gibidir
                        'Volkan
                        'Yurtseven
                        'VolkanYurtseven değil
                            
                            

Eğer yazdırılan metinlerin ardışık yazdırılması isteniyorsa aşağıda anlattığım TextStream nesnesini kullanmanız gerekir.

Şimdi veri yazdırmaya ait küçük bir kod yazalım.

                    
                            Sub DosyaYazTekSatır()

                            tamadres = "C:\Users\volkan\Desktop\denemeler\dosya2.txt"
                            ff = FreeFile ' o an uygun olan dosya numarası verilir. 

                            Open tamadres For Output As ff 

                            Print #ff, "bu ilk satır"
                            Print #ff, "bu da ikinci satır"

                            Close ff 'kapatırken kaydeder, ayrı bir save işlemi yoktur

                            End Sub
                                
                                

NOT: Eğer dosya mevcut değilse otomatikman oluşturulur, varsa ezilir ve üzerine yazılır.

Varolan dosyaya ekleme yapmak

Varolan bir dosyanın sonuna ekleme yapmak istiyorsak bu işi Append deyimi ile yaparız. Eğer dosya mevcut değilse Outputta olduğu gibi otomatikman oluşturulur.

                    
                        Sub DosyaAppend()

                        tamadres = "C:\Users\volkan\Desktop\denemeler\dosya2.txt"
                        ff = FreeFile ' o an uygun olan dosya numarası verilir. 

                        Open tamadres For Append As ff 

                        Print #ff, "bu üçüncü satır"

                        Close ff 'kapatırken kaydeder, ayrı bir save işlemi yoktur

                        End Sub
                            
                            
Excelden okuyup dosyaya yazma

İçiçie iki For Next ile satır ve sütunlarda dolaşırız, araya "," veya istediğimiz başka bir ayraç ekleriz.

Aşağıdaki örnekte 10 satır 3 kolondan oluşan bir listeyi metin dosyasına yazdırıyoruz.

                    
                        Sub Exceldenyaz()

                        tamadres = "C:\Users\volkan\Desktop\denemeler\dosya3.txt"
                        ff = FreeFile

                        Open tamadres For Output As ff

                        For i = 1 To 10
                            For j = 1 To 3
                                If j = 3 Then
                                   satırmetin = satırmetin + Trim(Cells(i, j).Value)
                                Else
                                   satırmetin = satırmetin + Trim(Cells(i, j).Value) + ","
                                End If
                            Next j

                            Print #ff, satırmetin
                            satırmetin = ""

                        Next i

                        Close ff

                        End Sub
                            
                            
Metin değişikliği yapmak

Bazen tek bir dosyada bazense birçok metin dosyasında aynı anda bir metin değişikliği yapmak isteriz. Birçok dosyayı elde etmeyi bir önceki sayfada görmüştük. Bir döngü ile bu klasörleri/dosyaları elde ettikten sonra yapmanız gereken iş 4 aşamadan oluşur:

  • Önce dosyayı açmak
  • Metni okumak
  • Aradığımız metni bulup değiştirmek
  • Dosyaya tekrar yazdırmak
                    
                            Sub MetinDeğiştir()

                            Dim adres As String
                            Dim içerik As String

                            adres = "C:\deneme\deneme.txt"

                            Open adres For Input As 1
                            içerik = Input(LOF(1), 1)
                            Close 1

                            içerik = Replace(içerik, "abc123", "abc345")

                            Open adres For Output As 1
                            Print #1, içerik
                            Close 1

                            End Sub
                                
                                

Yapılan değişkliği illa dosyaya kaydetmek zorunda değilsiniz. Mesela benim bazı SQL'leri tuttuğum metin dosyalarım var, içinde değişkenlerin olduğu bölümler var. Bu dosyaları bir nevi şablon olarak tutuyorum, onların üzerinde değişiklik yapmıyorum, onun yerine dosyayı okuyup bi değişkene atıyorum ve onun üzerinde replace işlemi yapıp, SQL metni olarak işleme sokuyorum. En aşağıdaki örnekler bölümünde bu işlemi görebilirsiniz.

Dosyalara yazma ve okumanın bir diğer yolu da TextStream nesnesi yoluyladır.

Niye böyle bir yöntem daha var? Bu sınıf, aslında web sayfalarında VBScript diliyle yazılmak üzere tasarlanmış bir sınıftı ama sonradan VBA içinde de kullanıma alındı. O yüzden Scripting Runtime library'si içindedir ve references menüsünden eklenmesi gerekir.

Ben şahsen hem okunurluk hem de kullanım kolaylığı açısından TextStream nesnesini kullanmayı tercih ediyorum, ancak her zaman olduğu gibi başkalarının yazdığı kodları okumanız/kullanmanız gerekebileceği için her yöntemi bilmekte fayda var. Aşağıda göreceğiniz üzere TextStream'in bazı ek özellik ve metodları da onu ayrıcalıklı kılmaktadır.

Erişim & Yaratım

Bir TextStream nesnesine erişmek için FSO'nun CreateTextFile veya OpenTextFile metodlarını kullanabileceğimiz gibi File nesnesinin OpenAsTextStream metodunu da kullanabiliriz.

CreateTextFile

Syntax: fso.CreateTextFile(dosyadı,Overwrite?,UnicodeDesteği?)

Aşağıdaki kod ile varolan bir dosyayı, eğer mevcutsa üzerine yazdırarak (yani içini boşaltarak) Türkçe karakterleri de destekleyecek şekilde açıyoruz.

                    
                        'global fso nesnesinin var olduğunu düşünerek ilerliyoruz
                        Dim ts As TextStream
                        Set ts = fso.CreateTextFile("c:\deneme\deneme.txt", True, True)
                            
                            

Eğer ikinci parametreyi False olarak kullanmak yani dosya mevcutsa onu ezmeyelim istiyorsak, aşağıdaki gibi dosyanın varlığını kontrol ederek açmalıyız yoksa "dosya zaten mevcut" hatası alırız.

                    
                        If Not fso.FileExists("C:\Users\Volkan\Desktop\denemeler\deneme1.txt") Then
                           Set ts = fso.CreateTextFile("C:\Users\Volkan\Desktop\denemeler\deneme1.txt", False, True)
                           ts.Write ("merhaba")
                        End If
                            
                            
OpenTextFile

Syntax: fso.OpenTextFile(dosyadı,I/O tipi,MevcutDeğilseYaratılsınmı?,Format)

                    
                        Set ts = fso.OpenTextFile("C:\deneme\deneme.txt",ForWriting,True,TristateFalse)
                            
                            

I/O tipi, ForWriting açıldığında içerik ezilir. Bu CreateTextFile'ın ikinci parametresinin True olarak açılmasıyla aynı etkidedir.

ForReading ile okuma yaparsınız, yazmaya izin verilmez.

ForAppending ile en sona konumlanır ve oraya yazarsınız, böylece mevcut içerik silinmemiş olur.

Üçüncü parametreyi, dosya mevcut değilse yaratmak istediğinizde True olarak kullanırız. Eğer burası False ise ve aradığınız dosya yoksa hata alırsınız. O yüzden ya burayı True yapmalısınız ya da dosyanın mevcut olup olmadığını kontrol etmelisiniz. Mesela aşağıdaki kod ile, dosya mevcut ise sonuna ekleme yapmak istiyoruz, mevcut değilse yaratarak açıyoruz.

                    
                            If Not fso.FileExists("C:\Users\Volkan\Desktop\denemeler\deneme2.txt") Then
                                Set ts = fso.OpenTextFile("C:\Users\Volkan\Desktop\denemeler\deneme2.txt", ForWriting, True, TristateFalse)
                            Else
                                Set ts = fso.OpenTextFile("C:\Users\Volkan\Desktop\denemeler\deneme2.txt", ForAppending, False, TristateFalse)
                            End If
                                
                                

Son parametre Unicode desteği ile olup olmayacağını belirtir.

OpenAsTextStream

Elinizde bir File nesnesi varsa bunun OpenAsTextStream metodunu kullanarak da metin dosyalarını açabilirsiniz. Gerçi File nesnesi için de yine bir FSO nesnesi gerekiyor. O yüzden her ikisini de yaratmak gerekecek. Eğer File nesnesini başka bir şey için kullanmayacaksanız boşuna bu zahmete gerek yok, direkt FSO ve onun metodları yeterli olacaktır.

Syntax: File.OpenAsTextStream(I/O modu,Format)

İki parametre de opsiyonel olup default değerleri sırasıyla ForReading ve TristateFalse'tur. Aşağıda bir örnek bulunmakta.

                    
                        'Örnek kullanım
                        Dim f As File
                        Set f = fso.GetFile("C:\deneme\deneme.txt")
                        Dim ts As TextStream
                        Set ts = f.OpenAsTextStream(ForReading, TristateFalse)
                            
                            
TextStream Üyeleri

Metin okuma şekilleri

                    
                            ts.Read(5) 'Bulunulan yerden itibaren 5 karakter okur
                            ts.ReadLine 'Bulunulan satırı okur
                            ts.ReadAll 'Tüm dosya içeriğini okur
                                
                                

Üç yöntemde de bir değişkene atama işlemi yapılmalıdır.

Ör: içerik=ts.ReadLine

Yazma şekilleri
                    
                            ts.Write(metin): Dosyaya metni yazar
                            ts.WriteLine(metin): Dosyaya metni yazar ve bir alt satıra geçer
                            ts.WriteBlankLines(5): Dosyaya 5 adet boş satır ekler
                                
                                

Line ile cursor'ın o anki satır numarasını elde ederiz.

Close metodu ile TextStream nesnesini kapatarız.

Dosyada okuma yaparken, belirli koşullar durumunda o satırı SkipLine ile atlayarak bir sonraki satıra geçebiliriz. Aşağıdaki kod ile, sayısal bir ifadeyle başlayan her şeyi bir collection'a atayıp en son da bunları yazdırıyoruz. Read ile bir karakter okuduktan sonra kalanını ReadLine yaparken başına ilk okuduğumuz kısmı eklediğimize dikkatinizi çekmek isterim. Örnek dosyamız aşağıdaki gibi olsun:

1-birinci satır
2-ikinci satır
falanfilan
3-üçüncü satır
falanfilan
4-dördüncü satır

                    
                                Sub Satıratla()
                                Dim ts As TextStream
                                Dim col As New Collection

                                Set ts = fso.OpenTextFile("C:\Users\Volkan\Desktop\denemeler\deneme1.txt", ForReading, False, TristateMixed)

                                Do
                                    kelime = ts.Read(1)
                                    If IsNumeric(kelime) Then
                                       col.Add kelime + ts.ReadLine
                                    Else
                                       ts.SkipLine
                                    End If
                                Loop Until ts.AtEndOfStream

                                For Each Item In col
                                    Debug.Print Item
                                Next Item   
                                End Sub
                                    
                                    

Çıktı ise şöyle olacaktır:

1-birinci satır
2-ikinci satır
3-üçüncü satır
4-dördüncü satır

Hepsi bir arada bir örnek
                    
                        Sub çeşitli_üyeler()
                        Dim ts As TextStream
                        Const dosya As String = "C:\Users\Volkan\Desktop\denemeler\ts_üyeler.txt"
                        Set ts = fso.CreateTextFile(dosya, True, True)

                        ts.WriteLine ts.Line & "-" & Now
                        ts.Write ts.Line & "-": ts.WriteBlankLines (1) 'Dosyaya 1 adet boş satır ekler
                        ts.WriteLine ts.Line & "-" & Environ("username")
                        ts.WriteLine ts.Line & "-" & "selam"
                        ts.WriteLine ts.Line & "-" & "naber"

                        Debug.Print ts.Line
                        ts.Close

                        Set ts = fso.OpenTextFile(dosya, ForReading, False, TristateMixed)
                        x = ts.ReadLine ' Bulunulan satırı okur
                        ts.skipline 'ilgili satırı atlar
                        y = ts.Read(5) 'Bulunulan yerden itibaren 5 karakter okur, artık 3. satırdayız: 3-Vol
                        z = ts.ReadAll 'Cursordan itibaren tüm dosya içeriğini okur, baştan itibaren değil :kan4-selam5-naber

                        Debug.Print z

                        End Sub
                            
                            
Otomasyon süreçlerinde Logger kullanımı

Diyelim ki aşağıdaki prosedür günün belirli saatlerinde çalışıyor. Çalışmanın belirli aşamalarını (kritik önemde veya ana işlerin öncesinde/sonrasında) kayıt altına alıyoruz. Ayrıca bir hata oluşursa yine bunu da kayıt altına alalım.

Otomasyon süreçlerinde Log tutmanın bir alternatifi kendinize veya ilgili kişilere mail attırmak olacaktır. Ancak çalışan çok fazla iş varsa mail kalabalığında boğulursunuz. O yüzden log sistemi daha güzel bir seçenektir.

Şimdi aşağıdaki örnekte Log dosyamızda Tarih/Saat, Kullanıcı, bilgisayar adı, rapor adı, log tipi, varsa hata kodu, açıklama kolonları olmak üzere 7 kolon bilgi bulunmaktadır. Bunun ilk 3'ü Logger fonksiyonu içinde dinamik olarak ele alınmakta, son 4 parametre ise Logger fonksiyonuna KrediRaporu modülünden argüman olarak gönderilmektedir. Diğer hususlar şöyledir:

  • Rapor ismi toplamda 50 hane olacak şekilde ayarlanır. 50'den kısa olan rapor isimleri için başına 50'ye tamamlanacak kadar boşluk eklenir. Bunun amacı datayı Excel'e aktardığınızda aynı hizada görünmelerini sağlamaktır. Bu sizin dünyanızda daha yüksek bir sayıya ayarlanabilir.
  • Bilgisayar ismi de yine aynı şekilde 10 haneye tamamlanmaktadır. Bu da sizin dünyanızda daha yüksek ayarlanabilir.
  • Hata yoksa hata kodu olarak 0 gönderilmektedir.
                    
                            '*****Logger'ı çağıran prosedür*****
                            Sub KrediRaporu()

                            On Error GoTo hata
                            raporLoggerAd="KrediRaporu"

                            'çeşitli işler
                            Logger WorksheetFunction.Rept(" ", 50 - Len(raporLoggerAd)) & raporLoggerAd, "OK", 0, "Bölme işlemi başlayacak"
                            'çeşitli işler
                            Logger WorksheetFunction.Rept(" ", 50 - Len(raporLoggerAd)) & raporLoggerAd, "OK", 0, "Bölme işlemi bitti"
                            'çeşitli işler
                            Logger WorksheetFunction.Rept(" ", 50 - Len(raporLoggerAd)) & raporLoggerAd, "OK", 0, "Rapor başarıyla çalıştı"

                            Exit Sub
                            hata:
                            Logger WorksheetFunction.Rept(" ", 50 - Len(raporLoggerAd)) & raporLoggerAd, "Hata", Err.Number, Replace(Err.Description, vbNewLine, vbNullString)

                            End Sub

                            '*****Logger prosedürümüz*****
                            Sub Logger(rpr As String, logtip As String, hatano As Integer, açıklama As String)

                                On Error GoTo hata

                                Dim dosya As String
                                Dim dosyano As Variant

                                dosyano = FreeFile
                                dosya = gunlukklasor + "\GünlükRaporlarLog.txt"

                                Open dosya For Append As #dosyano
                                Print #dosyano, CStr(Now), Environ("UserName"), WorksheetFunction.Rept(" ", 10 - Len(Environ("computername"))) & Environ("computername"), rpr, logtip, hatano, açıklama
                                Close #dosyano  

                                Exit Sub

                            hata:

                            Call mail_logger_hata(rpr, alicilar) 'Log prosedüründe bir şekilde hata önceden berlirlenmiş alınırsa alıcılara özel formatta mail atılır

                            End Sub
                                
                                
Kokpit uygulamalarında Logger kullanımı

Userform konusunda gördüğümüz Kokpit uygulamalarında, uygulamayı kullanan kişilerin aktivitelerini aşağıdakine benzer bir kod ile kayıt altına alabiliriz.

                    
                                'Form üzerindeki bir butona tıklanınca
                                Sub Btn_KrediRaporAc()
                                On Error Goto hata
                                   'rapor açma kodları  
                                   Rapor="KrediRapor"
                                   frekans="Günlük"
                                   Call detayraporlogu(Rapor, frekans)

                                Exit Sub
                                hata:
                                On Error Goto -1
                                On Error Goto hata2

                                'burada hata kaydını tutan bir log kaydı(aşağıdaki log prosedürünü gölgede bırakmasın diye detayına girmedim)
                                Exit Sub

                                hata2:
                                'Diskte yer olmaması, veya kullanıcının ilgili diske yazma yetkisinin olmaması gibi bir sebeple hata olması durumunda
                                Call LogHata 'bu sefer maille size bilgilendirme yapılır
                                End Sub

                                '*****Logger prosedürümüz*****
                                Sub detayraporlogu(ByVal Rapor As String, ByVal frekans As String)

                                    If Environ("UserName") = sizinuserınız Then Exit Sub 'kendimizi loglamıyoruz

                                    i = FreeFile
                                    Open adres & "Kokpitlog_detayrapor.txt" For Append As i
                                    Print #1, Environ("UserName"), Date, Time, frekans, Rapor
                                    Close #1

                                End Sub
                                    
                                    

Daha sonra bu text dosyasını bir Excel dosya içine aktarır veya her açıldığında refresh olan bir bağlantı kurarak gelen data üzerinde pivot tablolarınızı oluşturabilirsiniz. Metin dosyalarından bağlantı kurmak için buraya bakabilirsiniz.

Logger içinde hata

Bir sebeple logger fonksiyonu içinde de hata olursa bunu da başka bir hata bloğuyla ele alabilirsiniz. Veya ana gönderici modülde On Error GoTo -1 deyip 2. bir hata bloğu açabilirsiniz. Yukarıdaki ilk örnekte Logger fonksiyonu içinde hata bloğu ile yakaladık. İkinci örnekte ise ana prosedürde On Error GoTo -1 yöntemini kullandık.

Settings işlemleri

Bir dosyadan bir database'in kullanıcı adı ve şifresini okuma, veya bir dosyanın path'ini okuma gibi işlemler de bu sayfada öğrendiklerimizle yapılabilir. Diyelim ki jenerik bir Add-in yaptınız. Bu Add-indeki makrolardan bir tanesi bir klasördeki bir Excel dosyasını açacak. İşte bu Excel dosyanın yerinin sabit olmasının mümkün olmadığı, bunun hangi klasörde olacağını kullanıcıya bırakmanız gereken durumlar olabilecektir. SettingforAddin1.txt gibi bir dosya içine bu klasörün tam path'i yazılabilir. Hatta buna birden fazla dosya için birden fazla klasör de eklenebilir. İstenirse ";" ile ayırılır, istenirse satır satır yazılır, hiç farketmez. Yukarıdaki yöntemlerden biriyle ilgili adresi elde etmek oldukça kolaydır.

SQL metinlerini değiştirme

Diyelim ki raporlama araçlarınız çok hantal ve katı. Siz de gerek kendiniz gerek departmanınız için Excel içinden çalışan hızlı ve esnek bir raporlama platformu oluşturdunuz. İlgili raporların SQL'ini bir metin dosyası içine koydunuz. Kullanıcıya tarih ve müşteri listesi gibi sorular sordurarak dosyadaki parametrik kısımlarla kullanıcının verdiği cevapları replace ettirerek nihai SQL'inizi elde edersiniz. Böylece uzun bir SQL'i VBA içine satır satır yazmaktan kurtulmuş olursunuz. VBA içine de SQL kodu yazılabilir ama bu hem kodun uzun ve çirkin görünmesine neden olur hem de çok zahmetli bir iştir, özellikle SQL onlarca hatta yüzlerce satırdan oluşuyorsa.

                    
                                    Sub SQLDeğiştir()

                                    tarih=InputBox("tarihi girin")
                                    If tarih=vbNullString Then Exit Sub

                                    adres="C:\SQLller\kredi.txt"
                                    Open adres For Input As #1
                                    içerik=Input(LOF(1),1)
                                    Close #1

                                    strSQL=Replace(içerik,"trh",tarih) 'SQLi elde ettik
                                    'bundan sonra SQL'i çalıştıracak kodlar devreye girer

                                    End Sub