> Delphi > Stream’de Uzmanlaşalım… (Bölüm 2)

Stream’de Uzmanlaşalım… (Bölüm 2)

Geçen bölümde stream’e giriş yaptık. Ve değişik veri tipleri ile stream üzerindeki okuma ve yazma işlemlerini gördük. Bu bölümde stream kullanımının sadece dosya okumak-yazmak olmadığını da göreceğiz. Ayrıca .net ve vcl.net ortamında stream kullanımından da bahsetmeye çalışacağız.

Hafıza Bölgesinde Stream Kullanımı

Takdir edersiniz ki en hızlı stream verisi hafızada bulunan stream verisidir. Yani bir hafıza stream nesnesi her halukarda okuma-yazma işlemleri dosya ve veritabanından hızlı çalışacaktır. Bu durumda eğer bir stream ile çok fazla okuma-yazma işlemleri gerçekleştiriliyorsa, ilk başta bir hafıza streami kullanılmalı ve stream ile işimiz bitip son durumu kaydetmek istediğimizde bu hafıza streaminden başka bir stream nesnesine aktarım yapılması en doğru işlem olacaktır. Aynı şekilde stream verisi üzerinde çok miktarda Seek işlemi yani stream işaretçisinin pozisyonunu değiştirme işlemi gerçekleştiriyorsanız, bu durumda yine stream verisinin tamamını bir hafıza bölgesine aktarmalısınız.

Aşağıdaki örneğe göz atalım:



		

Gördüğünüz gibi TMemoryStream’in Create oluşturucusu hiç bir parametre almıyor. Burada ekstradan yazma işleminden sonra Position := 0 ile stream işaretçisini başa getiriyoruz. Çünkü yazma işleminin sonunda işaretçi pozisyonu kayacaktır. Okuma işlemini yapabilmemiz için yine işaretçiyi başa getirip okutuyoruz. Aynı işlemi Seek metodu ile de yapabiliriz. Ek bir not olarak, Seek metodu Position’dan daha hızlı çalışmaktadır.

Hafıza streami kullanmak, oluşturulması esnasında hiç bir parametre gerektirmediğinden, diğerlerine nazaran daha kolay ve pratiktir. Bu yüzden yapacağımız yüksek yoğunluktaki stream işlemlerini TMemoryStream ile yapmamız bizim yararımıza olacaktır. Özellikle Seek işlemlerinde yani pozisyon değiştirme işlemlerinde hafızadan faydalanmak önemli bir performans artışına sebep olacaktır.

Stream’lerin Aktarımı ve Kopyalanması

Stream verileri ile okuma-yazma işlemlerinden sonra yapılan en önemli işlem de bir stream’in başka bir stream verisi üzerine aktarılmasıdır. Mesela bir dosyayı hafızaya almak isteyebilirsiniz. Veya hafızadaki bir veriyi veritabanına aktarmak isteyebilirsiniz. Bu durumda her stream fonksiyonunda bulunan CopyFrom metodu kullanılır.

Aktarım işleminde basit bir metodu kullanmaktan öte, bir noktaya dikkat edilmesi şarttır. CopyFrom metodu ve bunun gibi bir çok metod, stream işaretçisinin bulunduğu pozisyondan itibaren işlemeye başlarlar. Aşağıdaki örneğe bir göz atalım:



		


İlk yaptığımız işlem bir karakter dizisini hafızaya almak oldu. Ardında bu hafıza streamini dosya üzerine kopyaladık. Burada dikkat edilmesi gereken nokta Position := 0 kısmıdır. Hafızaya karakter dizisinin yazılmasından sonra stream işaretçisi sona kayar. Böylece sonrasında gelen CopyFrom gibi metodlar bu pozisyondan itibaren işlem yapmaya başlarlar. İşaretçi sonda olduğu için CopyFrom kopyalayamaz ve bir istisna hatası çıkarır. İşte bunu önlemek için işaretçiyi başa alıyoruz ve hafıza streaminin tamamını dosya üzerine aktarıyoruz.

Kısacası CopyFrom metodu, kopyalanacak olan streamin işaretçi pozisyonundan itibaren, sizin belirlediğiniz uzunluk kadar stream’den okur ve diğer streame aktarır. Tek dikkat etmemiz gereken nokta kopyalayacağımız kaynak stream’in mevcut işaretçi poziyonudur. Eğer işaretçi poziyonu sonda ise CopyFrom kaynak stream’den veri okuyamayacak ve hata meydana gelecektir.

Nesneler ve Bileşenleri Okuyup Yazmak

Nesneleri, stream üzerine yazmak denildiğinde ilk akla gelen record verileri gibi okuyup yazmaktır. Halbuki nesneler, her ne kadar benzese de, record verilerinden çok farklıdır ve karışıktır. Bu yüzden direk olarak bir sınıf ya da nesne stream üzerine aktarılamaz. Ancak sizin belirlediğiniz kısımları ayrı ayrı, önceden öğrendiğimiz okuma-yazma işlemleri ile halledebilirsiniz.

Fakat bileşenlerde durum biraz farklıdır. Daha doğrusu TPersistent sınıfından türeyen bütün sınıflarda durum biraz farklıdır. TStream sınıfında, bileşenlerin özelliklerini stream üzerine alabilmek için ReadComponent ve WriteComponent metodları mevcuttur. Bu metodlar sayesinde bileşenler stream verileri üzerine aktarılabilirler. Ki, Delphi IDE’si bunu bol bol kullanmaktadır. Eğer bileşen yazımı ile ilgili 3 bölümlük makaleyi okumuş iseniz bileşenlerde bir özelliğe kaydedebilme özelliği kazandırmıştık. Yani özelliğin kaydedebilme özelliği yoksa stream üzerine aktarılamazlar. Özelliklerin kaydedilebilme işlemine burada değinmeyeceğiz. Ama isterseniz, bileşen yazımı ile ilgili makaledeki kolleksiyon ve binary özellikler kısmına göz atabilirsiniz.

Bileşenlere bu özelliği kazandıran TPersistent sınıfıdır. TPersistent sınıfı ile ilgili daha fazla bilgi alabilmek için yardım dosyalarına göz atabilirsiniz.

Yeni bir form açalım ve bir button ekleyelim. Buttonun OnClick olayına aşağıdaki kodları yerleştirelim:



		

Bu programı çalıştırıp button’a basarsanız, C: bölümde deneme.txt isimli bir dosya göreceksiniz. Bu dosyayı bir hex editor ile açıp kontrol edebilirsiniz. Ama dosyaya baktığınızda TButton’a ait tüm özelliklerin olmadığını göreceksiniz. Çünkü burada sadece bileşenin değişmiş olan özellikleri kaydedilir. Her özellik bir default değere sahiptir. Ve bu değer değişmiş ise, WriteComponent metodu bunu stream üzerine yazacaktır.

Şimdi bu dosyadaki Button1 bileşenini okutalım ve form üzerinde oluşturalım. Bunun için yeni bir uygulama açalım ve içinde Button1 isimli bir button olmamasına özen gösterelim. Çünkü birazdan bu bileşeni dosyadan biz oluşturacağız.

Form üzerine bir button ekleyelim ve ismine Button2 diyelim ve Caption olarak "bileşeni dosyadan oku" gibi bir şey yazalım. Ardından buttonun OnClick olayına aşağıdaki kodları yerleştirilem:



		


Programı çalıştırıp Button2’ye tıklarsanız form üzerinde önceden kaydettiğimiz Button1 bileşenini göreceksiniz.

Önceden de dediğimiz gibi TPersistent olmayan nesneleri direk olarak stream olarak yazmak ve okumak mümkün değildir. Fakat kendinizin tanımlayacağı formatta, stream’den okuma ve stream’e yazma gibi fonksiyonlar ile nesnelerinize bu özelliği kazandırabilirsiniz. Zaten TPersistent sınıfının da yaptığı işlem budur. TPersistent sınıfına fazla girmek istemiyorum, fakat merakı olanlar TPersistent ile beraber TFiler, TReader gibi sınıflara yardımdan göz atabilirler.

Ek olarak bu konuda söyleyebileceğim bir tecrübem de şudur. İster VCL içinde olsun, ister başka bir yerden bulacağınız bir bileşen veya bir sınıf olsun, eğer stream ile çalışıyorlarsa şu 4 metod bunlarda bulunacaktır. LoadFromStream, LoadFromFile, SaveToStream, SaveToFile.

Buna tecrübe dedim çünkü literatürde bu metodlar aynı isim ve parametrelerle bulunacak diye bir şart yoktur. Fakat VCL’de bulunan bileşenlerde bolca kullanılan bu metodlar, diğer 3. parti bileşen ve sınıflarda da kolaylık ve alışkanlık olması açısından isimlerini ve yapılarını korumuştur. Eğer bir sınıf stream ile işlem yapıyorsa bilinki bu sınıfta, yukarıda bahsettiğimiz 4 metod bulunacaktır.

Sizler de yazacağınız sınıflarda bu metodları aynı isim ve yapıda kullanırsanız, sınıfınızı ya da bileşeninizi kullanacak olan kişiler zorlanmayacaktır. Bu metodların tanımlamasını VCL’de herhangi bir sınıf ya da bileşenin tanımlamasından kopyala yapıştır ile alabilirsiniz. Sadece burada değişecek olan kısım LoadFromStream ve SaveToStream metodlarıdır. Bu metodların içeriğini kendinize göre yeniden oluşturmalısınız.

 

Resource Verilerini Okuyup Yazmak

Resoruce verileri, kısaca açıklamak gerekirse, exe ya da dll dosyanız içine gömülen verilerdir. Bu veriler resim, yazı, icon, form olabileceği gibi herhangibir formatta stream verisi de olabilir.

Resource dosyaları ".RC" uzantılı bir dosyadan herhangi bir resource compiler ile derlenir. Bu derleme sonucunda ".RES" uzantılı bir dosya oluşacaktır. RES dosyalarını istediğiniz bir resource derleyicisi ile oluşturabilirsiniz. Çünkü bu res dosyaları derleyiciden bağımsızdır. Fakat RC dosyasının grameri değişiklik gösterebilmektedir. Biz bu makalede resource verilerini derlemek için delphi ile beraber gelen brcc32 derleyicisini kullanacağız. İsterseniz Visual Studio veya benzeri bir başka resource manager ile RES dosyaları oluşturabilirsiniz. Eğer Delphi 2009’a sahip iseniz, yeni "Resource Manager" ile daha rahat resource dosyaları oluşturabilirsiniz.

Delphi 2009 - Resource Manager Delphi 2009’da menüden Project/Resources… altından ulaşabilrsiniz.

Biz elimizde Delphi’den başka bir şey olmadığını düşünerek işe koyulalım ve resource dosyamızı oluşturalım.

Notepad ile yeni bir yazı dosyası oluşturalım ve içine bir yerlerden uzun bir paragraf bulup yapıştırılım. Bunu yazi.txt ismi ile kaydelim. Aynı klasöre başka bir yazı dosyası daha oluşturalım ve içine aşağıdakileri yazalım:

yazi RCDATA yazi.txt 

Daha sonra bu dosyayı "yazi.rc" ismi ile aynı klasöre kaydedelim.

Burada ilk yazdığımız kelime resource’a verdiğmiz isimdir. İleride bu isme göre resource verimizi kullanacağız. İkinci kısımda RCDATA ile verimizin tipini belirledik. Burada RCDATA’nın dışında BITMAP, CURSOR ve ICON gibi ayrı ayrı tipler kullanılabilir. Bunların tam listesi için internette araştırma yapabilirsiniz. (http://msdn.microsoft.com/en-us/library/aa381043(VS.85).aspx). En sondaki kısım ise resource olarak kullanacağımız verimizin dosyasını giriyoruz.

Başlat/Çalıştır ile cmd yazıp entere basıp komut satırına geçelim. Buradan dosyaları kaydettiğimiz klasöre geçelim(msdos biliyorsunuzdur herhalde 🙂 ). Ardından aşağıdaki komutu yazıp entere basalım.

brcc32 yazi.rc

Bir problem oluşmadı ise aynı klasörede yazi.res isimli bir dosya göreceğiz.

Bu işlemlerden sonra Delphi’ye geçip yeni bir uygulama açalım. Yeni uygulamamızı .res dosyalarını oluşturduğumuz klasöre kaydedelim. Şimdi az önce oluşturduğumuz res dosyasını programımız içine gömmek için gerekli işlemleri yapalım.

Unit1’in kodlarını açalım ve uygun bir boşluğa aşağıdaki derleyici direktifini girelim:



		

Programızı derlediğimizde bu res dosyasında buluna bütün veriler, resource verisi olarak programımıza gömülecektir. İsterseniz bunu ResHack gibi herhangi bir resource yöneticisi ile kontrol edebilirsiniz.

Şimdi bu gömülmüş olan veriyi okumamız gerekiyor diyelim. Mesela az önce programımız içine gömdüğümüz yazi.txt dosyasını bir memo içine alalım ve gösterelim.

Form üzerine bir adet memo bileşeni ve bir adet button ekleyelim. Button’unun OnClick olayına şunları yazalım:



		

Programı çalıştırıp button’a basalım. Bir sorun çıkmadı ise memo bileşeninde yazi.txt dosyasındaki yazılı olan paragrafı göreceğiz.

Bu yaptığımız örnek ile görüyoruz ki; bir TResourceStream nesnesi, herhangi bir exe veya dll içindeki resource verilerine erişebiliyor. Create oluşturucusunda gördüğümüz ilk parametre resource verisini nereden çekeceğimizi belirliyor. Buna daha sonra değineceğiz. İkinci parametre olarak erişeceğimiz resource verisinin ismidir. Bunu RC dosyasını hazırlarken görmüştük. Aynı şekilde son parametre de RC dosyasında belirlenmişti. Bu son parametre ile resource verisinin tipini belirliyoruz. Tek fark olarak baş tarafına RT_ ön ekini getiriyoruz.

Sonraki işlem ise memo bileşenin Lines özelliğine streamdeki veriyi aktarıyoruz.

Bu mantığı kullanarak istediğiniz türde veriyi resource olarak gömebilir ve program çalışması anında kullanabilirsiniz. Bu yaptığımız örnek sadece mevcut programdan verileri çekebilir. Fakat başka bir dll ya da exe’den veri çekmemiz gerektiğinde ne yapacağız?

İşte bu durumda hInstance olarak girdiğimiz parametre değişecektir. Çünkü burada girdiğimiz parametre veriyi nereden çekeceğimizi daha doğrusu resource verisinini nerede olduğunu belirler.

Her program(exe, dll, ocx, ..) çalıştırıldığında windows tarafından bir handle numarası ile ilişkilendirilir. Delphi’de bu handle numarasına erişebilmek için hInstance isimli global bir değişkeni kullanıyoruz. Bu yüzden Create oluşturucusunda mevcut çalışan programımızın handle numarasını buraya birinci parametre olarak girdik.

Peki başka bir exe veya bir dll’in handle numarasını nasıl alırız?

Bunun için cevabımız LoadLibrary fonksiyonudur. Bu fonksiyon ile çağırdığımız herhangi bir program geçici olarak hafızaya yüklenir ve windows tarafından bir handle atanır. Bu handle numarası ise çıkış olarak döner. Eğer yükleme işlemi başarısız ise handle numarası 0 olarak dönecektir. Mesela yukarıda yaptığımız işlemleri bir dll içinden almaya kalkarsak nasıl yapacaktık?



		


Aynı işlemi exe, ocx gibi diğer çalıştırılabilir formatlar içinde yapabilirsiniz.

Artık herhangi bir veriyi exe içine gömüp okumayı öğrendik. Şimdi de bu işlemin bir benzerini veritabanlarında yapalım.

Veritabanında Stream Kullanımı

Artık buraya kadar öğrendiklerimizle herhangi bir stream verisini okuyup yazabiliriz. Burada yapacağımız işlem de pek farklı olmayacak. Bu yüzden hemen konuya girelim ve kısaca veritabanlarında nasıl stream kullanıldığını görelim.

Veritabanlarında bulunan tablolarda stream verilerini saklamak için alanımız BLOB tipinde olmalıdır. BLOB tipindeki alanlar binary veriler tutabilir. Fakat indeksli ve üzerinde çok arama tarama işlemleri yapılan bir tablomuz var ise bu BLOB alanlar veritabanı işlemlerini yavaşlatacaktır. Bu yüzden bu BLOB alanları başka bir tablo üzerine taşımak performansı artıracaktır.

Tabloda bulunan bir BLOB alana veri yazmak ve bu alandan veri okumak için TBlobStream nesneleri kullanılır. Kullanımı aşağıdaki gibidir:



		

Genel manada kullanım bu şekildedir fakat daha başka yöntemler ile de blob stream oluşturulabilir. Bu örnekte BlobAlan isimli bir alan hem okuma hem de yazma işlemleri için stream olarak bizim blob stream nesnemize atanmıştır. Burada sadece okuma işlemleri yapacaksak bmRead, sadece yazma işlemi yapacaksak bmWrite parametrelerini kullanmalıyız.

TStream’i .NET ve Delphi 2009’da Kullanmak

TStream sınıfı Delphi’nin bileşen mantığının temelini oluşturmaktadır. Delphi, .NET ortamına taşınırıken haliyle TStream sınıfı da ufak farklılıklar ile .NET ortamına taşınmıştır. Benim burada bahsedeceğim konu sadece bu küçük farklılıklar olacaktır. Geri kalan işlemlerde buraya kadar öğrendiğiniz bilgiler fazlasıyla yetecektir.

.NET ortamında Pointer işlemleri kullanılmadığından TStream sınıfı ve alt sınıfları için bir değişikliğe gidilmesi şarttı. Bu yüzden, TStream sınıfı .NET ortamına taşındığında Pointer işlemleri yerine, bu işlemlerin yerini tutan belirgin ve basit tipler için ayrı ayrı metodlar hazırlandı.

Mesela hatırlarsanız normalde TStream sınıfında bulunan ReadBuffer ile bir srting veri yazdığımızda string’i pointer olarak type cast yapıp parametre olarak giriyorduk. .NET’de pointer kullanmadığımız için ReadBuffer yerine artık aynı isimli ve sadece özel tipler için özdeşleştirilmiş bir metodumuz var. Bu metodu kullanarak rahat bir şekilde pointer kullanmadan işlemlerimizi aynı şekilde yapabiliriz. Tabi bu daha önce yaptığımız Win32 TStream sınıfına göre çok rahatlık getirmektedir. Bu da hiç şüphesiz .Net’in getiridiği rahatlıklardan birisi.

ReadBuffer ver WriteBuffer metodlarından bir kaçındaki değişlikliklere göz atalım:



		


Tam liste için lütfen Borland.Vcl.Classes unitinde bulunan TStream sınıfına ya da yardıma göz atınız.

Gördüğünüz gibi aynı ReadBuffer metodu, overload yöntemi ile bir çok kez tanımlanmış. Biz bunlardan ihtiyacımız olanı seçip kullanacağız. Boolean ve Integer yazımı için tek bir adet parametre gerektirdiğine dikkat ediniz.

Diyelimki stream üzerine yazdıracağımız veya okuyacağımız veri çeşidine uygun bir metod bulunmamakta. Bu durumda verimizi bir byte dizisi gibi düşünüp ona göre davranacağız. Bu durumda verimizi TBytes’a yani "array of Byte" tipinieçevirmemiz gerekmektedir. Bunun için herhangi bir for döngüsü tanımlayarak bu işlememizi yapabiliriz.

Integter ile ilgili metodlara bakarsanız, en sonda fazladan Count parametresi alan bir metod yerleştirdim. Bütün metod çeşitlerinde alternatif olarak bu ikininci parametreye sahip olan metodlar mevcuttur. Bu parametreyi mesela Integer için normalde 4 byte ayrılmasına rağmen siz 10 byte yer ayırmak istediğinizde kullanablirsiniz.

Bu metodlara baktığınızda string ile ilgili bir özel metodun olmadığını farkedeceksiniz. Peki string veriyi nasıl yazacağız?

Bu durumda veriyi hangi encode’da yazacağımız veya okuyacağımız önemli. Veriyi istersek UTF8 formatında istersek UTF16 veya ANSI olarak okuyabilir ve yazabiliriz. Bu durumda string verimizi byte dizisine çeviren veya byte dizisini string verisine çeviren bir yönteme ihtiyacımız var. Aşağıdaki örneğe göz atalım:



		

Gördüğünüz gibi string verimizi utf-8 olarak stream üzerine attık ardından memo1 ile ekranda gösterdik. Bu işlemi yapabilmek için string verisini uygun bir byte dizisine çevirmemiz gerkiyordu. Bunun için System.Text alanında bulunan Encoding sınıfını kullanıyoruz. Bu sınıfı kullanabilmek için uses’a System.Text’i eklemelisiniz.

İsterseniz bu yazma işlemini Encoding.Unicode ile utf-16 ya da diğer adıyla unicode olarak, isterseniz Encoding.Default ile işletim sisteminin varsayılan ansi karakterleri olarak yazıp okuyabiliriz. Önemli olan string bir şekilde byte dizisine çevrilmiş olması gerekmektedir. Ayrıca yazma ve okuma işlemlerinde aynı tip encode formatını kullandığınızdan emin olun. Yani ya her ikisinde de Unicode ya da her ikisinde de UTF8 kullanın.

Eğer TBytes’dan stringe çevirim yapmamız gerekirse bu durumda aşağıdaki metodu kullanıyoruz:



		

Gördüğünüz gibi .net ile bu işlemleri yapmak çok basit. Ayrıca en sonda stream’i free yapmasanız da Garbage Collector sizin için bunu yapacaktır. Fakat TFileStream kullanıyor ve dosyaya fmShareExclusive gibi kilitleyici bir parametre ile ulaşıyorsanız, stream nesnesini öldürmeden veya program kapanmadan, başka bir program dosyaya ulaşamaz, dosya kilitli kalır.

Bu bölümde bahsetmek istediğim başka bir konu da bu işlemleri Delphi 2009 ve üstünde yapmak. Burada bahsediyorum, çünkü bahsedeceğimiz bu konu .net ile de ilgili bir konu.

Aslında daha önceden gördük ki; bir stringi stream’e yazmak için stream’in kaç karakter olduğundan çok ,boyutunu bilmemiz gerekiyor. Bu yüzden ansi ya da ascii stringlerde boyut olarak her zaman Length(string) şeklinde aldık. Çünkü ansi stringlerde boyut = karakter sayısıdır. Fakat unicode olan stringlerde bu durum biraz farklıdır. Unicode olan stringler 1 byte değil, 2 byte yer kaplarlar. Bu yüzden WideString gibi unicode stringler ile uğraştığımızda artık boyutumuz Length*2 olmaktadır. Bildiğiniz gibi Delphi.Net ve Delphi 2009 ve yukarısı derleyicilerde "string" ve "Char" tipi unicode formatındadır. Bu derleyicilerde ansi olarak veri tanımlamamız gerektiğinde AnsiString, AnsiChar, PAnsiChar gibi tipleri kullanmalıyız. Aksi durumda bu derleyicilerde bir Char tipi 2 byte yer kaplar. Bu konu ile ilgili daha önceden örnek verdiğimizden bu konuyu burada bitiriyorum.

.NET Stream Nesnesinin Kullanımı

TStream’e ek olarak, .net’de aynı mekanizma bulunmaktadır. Neden bilmiyorum ama .net’de bulununa bir çok teknoloji Delphi ile benzerlik göstermektedir. Belki de c# ve .net’in fikir babası olan Anders Hejlsberg’in delphi’nin ilk temellerini atmasından kaynaklanıyor olabilir. Her neyse biz konumuza dönelim.

Aslında bu konu çok uzun anlatılabilecek bir konu ve burada bahsetmemiz makaleyi bir üçüncü bölüme bile taşıyabilir. Ki bence buna gerek yok. Ben sadece TStream ile arasındaki benzerlikleri gösterip, nasıl kullanıldığına dair bir örnek vermek istiyorum.

Bu bölümü VCL.Net kullanmak istemeyip saf .net kodu oluşturmak isteyenler veya Delphi Prism kullananlar için yazmak istedim. Aksi takdirde TStream sınıfı çoğu kez işimizi rahat bir şekilde görmektedir. Fakat bazen kullandığımız .net sınıfları .net’in stream sınıflarına ihtiyaç duyabilmektedir.

VCL’de bulunan bazı stream sınıfları yerine .net’de bulunan karşılıklarını şöyle sıralayabilriiz:

TFileStream => FileStream
TMemoryStream => MemoryStream
TIdTCPClient => NetwrokStream

vs..

Tabi bu stream sınıflarının metodları benzerlik gösterse de kullanımları farklıdır. Bu stream sınıflarını kullanabilemek için uses’a System.IO alanını eklemelisiniz. Biz buradan MemoryStream ile ilgili bir örnek verelim:



		

Gördüğünüz gibi kullanım olarak TStream’den farklı değil. Fakat Write metodunu TStream’de olduğu gibi bir çok çeşidi olduğunu zannetmeyin sakın. Çünkü MemoryStream sınıfında Write metodunun sadece iki adet varyasyonu mevcut. Bu metodda ilk parametre byte dizisi, ikinci parametre nereden itibaren yazılacağı yani ofset ve üçüncü parametre olarak yazdırılacak verinin uzunluğu giriliyor.

Bunun dışında bu string ve binary değerleri rahat bir şekilde okuyup yazabilmek için çeşitli ek sınıflar kullanılmaktadır. Mesela BinaryWriter ile binary değerleri stream üzerine yazabiliriz veya StreamReader ile streamden karakter verilerini okuyabiliriz. Aşağıdaki örneğe göz atalım:



		

Yukarıda yaptığımız işlemin aynısını burada StreamWriter sınıfı ile gerçekleştirdik. İşte burada StreamWriter sınıfının Write metodunda bir çok varyasyon mevcuttur. Bu varyasyonlara yardım dosyalarından ulaşabilirsiniz. Mesela bir Integer değer yazmak için yine StreamWriter’a ait Write metodunu kullanmamız kafidir.

Bunun dışında bir de kullanabileceğimiz BinaryWriter ve BinaryRead sınıfları mevcuttur. Bu sınıflar ise binary verileri okuyup yazmak için kullanılırlar. Ama kullanım aynı olduğu için bu konuya da girmeyeceğim.

Burada en son olarak BufferedStream sınıfından bahsetmek istiyorum. Bu stream ile okuma ve yazma işlemlerini başka bir stream üzerinde buffer’layarak daha hızlı işlemler yaptırabilirsiniz. Hatırlarsanız TMemoryStream sınıfından bahsederken, bu sınıfı diğer stream sınıflardaki okuma yazma işlemleri yerine kullanılabileceğinden ve bunun performansı artırdığından bahsetmiştik. İşte burada TMemoryStream bir buffer vazifesi görmektedir.

Mesela bir dosyaya bir çok veri yazılacak, ve bu veriler parça parça yazılacak. Ayrıca bu dosya stream’i üzerinde bir çok seek işlemi yani ileri geri alma işlemleri yapılacak. İşte bu durumda direk olarak TFileStream gibi bir dosya stream nesnesi ile uğraşmak yerine hafıza stream’leri ile uğraşmamız işlemlerimizin performansını önemli derecede artıracaktır. Yapacağımız stream işlemlerini bir hafıza stream’i üzerinde gerçekleştirip, en son işlemimiz bittiğinde hafıza stream’ini ilgili stream nesnesine aktarmak en akıllıca yöntemdir. İşte bu yönteme buffering ya da tamponlama tekniği denir.

İşte bu anlattığımız tekniği BufferedStream nesnesi gerçekleştirmektedir. Aynı işlemi ekstra bir memory stream tanımlayarak siz de oluşturabilirisiniz, hatta bu makalede buna benzer örnekleri çok gördük.

BufferedStream sınıfını kullanmak isteyenler, yardım dosyalarında ve msdn’de tanımlamasına bakabilirler. Artık stream mantığını kafanızda yerleştirdiğinize göre burada kullanımını vermek artık sıkacaktır.

Sonuç

Bir makalenin daha sonuna geldik. Bu makale serisinde VCL ve .net’de kullanılan stream sınıflarına değinmeye çalıştık ve bu sınıfların kullanımına dair çeşitli örnekler vermeye çalıştık.

Tabi ki burada verdiklerimiz stream için en temel konulardır. Bu makaleyi okuduktan sonra artık kafanızda stream’e ait somut düşüncelerin oluştuğunu zannediyorum. Ve bundan sonra önünüze gelecek olan bir çok stream işlemini rahat bir şekilde halledebileceğinizi umut ediyorum.

Fikir, eleştiri ve yorumlarınızı bekliyorum. Ayrıca makaledeki hataları bildirirseniz sevinirim.

Hayırlı çalışmalar.

Fatih Tolga ATA, Şubat 2009

» Tags: , , , , , , , , , , ,

5 Comments

  • At 2009.04.05 16:24, Murat said:

    Güzel.

    • At 2015.12.23 14:34, Erol Akyüz said:

      Eline emeğine sağlık şu ana kadar okuduğum en yararlı makalelerdi…

      • At 2016.01.15 15:49, Erol Akyüz said:

        Resources işlemini brcc32.exe olmayan bir bilgisayara nasıl yaptırabiliriz? Yani exe’imizin içine resources yapmayı da gömmek istiyorum. Amacım database bilgilerini program ilk kurulduğunda 1 defa bir dosyaya yazdıracağım ve sonra o dosyayı exe’ye gömeceğim böylelikle database bilgileri de güvenli hale gelecek.
        erolakyuz@hotmail.com
        Saygılarımla;

        • At 2016.11.20 00:46, Coder71 said:

          hocam emeğine sağlık gerçekten faydalı bir çalışma olmuş yalnız byte tipi dosya okuma yazmayı da anlat saymışsınız çok güzel olurmuş ama yapacak bir şey yok buradan türetmeye çalışacağım inş. başarırım 🙂

          • At 2017.04.05 23:59, Ufuk said:

            Allah razı olsun.

            (Required)
            (Required, will not be published)