Go İle Dosya Okuma ve Yazma İşlemleri - Golang
5 min read

Go İle Dosya Okuma ve Yazma İşlemleri - Golang

Go İle Dosya Okuma ve Yazma İşlemleri - Golang

Go dosya okuma, yazma, düzenleme ve silme işlemleri ile her türlü dosya üzerinde rahatlıkla işlemler gerçekleştirebilirsiniz. Golang, dosya işlemleri için farklı kütüphaneler kullanır ve dosyalarınızı yönetir. Bu dersimizde Go (Golang) ile çeşitli dosya işlemlerinin nasıl yapıldığını örnekleriyle göreceğiz.

Go, güçlü bir dildir ve Linux’un temeli olan Herşey Bir Dosyadır mottosu ile her türlü dosya tipi üzerinde başarıyla işlemlerinizi gerçekleştirebilir. Bu yazıya geldiğinizde aklınızda belki sadece txt ve json dosyaları vardı ama şunu belirtelim ki elinizde uzantısı ne olursa olsun her dosya üzerinde okuma, yazma ve düzenleme işlemleri yapabileceğinizi bilmenizi istiyorum. Siz sadece aşağıda anlatacağım gibi dosyanızı seçin ve işlemlere başlayın.

1- Dosya Oluşturma

Golang ile dosyalar üzerinde okuma, yazma, düzenleme ve silme işlemlerini görmeden önce nasıl yeni bir dosya oluşturabileceğimizi de görelim. Bunun için Create() methodunu kullanıyoruz.

file, err := os.Create("dosya.txt")
if err != nil {
    log.Fatal(err)
}

// Fonksiyon sonunda dosyayı kapat
defer file.Close()

Çok basit bir kullanımla dosya.txt isimli dosyamızı oluşturmuş olduk.

2- Dosya Okuma & Açma İşlemleri

Olayın özünü anlamak için bende txt dosyaları üzerinde çalışacağım ama şunu unutmayınız: Dosya olarak txt yerine png uzantılı bir dosyada seçebilirdim. Sonuçta her nesne bir dosyadır. Öyleyse şimdi ilk olarak dosyamızı seçelim ve okuyalım. Bunun içinde Open() veya OpenFile() fonksiyonlarından birini kullanabiliriz.

2.1- Open() ve OpenFile() Fonksiyonları Farkı

Dosya seçmek ve açmak için bu iki fonksiyondan birini kullanabileceğimizi söylemiştik. İki fonksiyon arasında ki fark kısaca;

  • Open() : Dosyaları sadece ReadOnly modunda açar.
  • OpenFile() : Dosyaları birçok kipte seçebilir ve birçok işlemi dosya üzerinde gerçekleştirebiliriz

2.2- Dosyayı Seçme

Aşağıdaki yöntemle dosyamızı seçiyoruz ve işlem kipini belirtiyoruz. Ayrıca dosya yoksa oluştururken verilecek dosya iznini de belirleyebiliriz.

file, err := os.OpenFile("deneme.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
    panic(err)
}

// Blok sonunda dosyayı kapat
defer file.Close()

Ana programımızda kullandığımız küçük bir kod parçacağı ile deneme.txt dosyamızı okuyoruz. Bu dosyayı seçerken dikkat ettiğiniz gibi önce dosya ismi, ardından işlem tipi (flag), ardından da dosya izni belirtilir. İşlem tiplerimizin neler olduğundan hızlıca bahsedelim çünkü bu kısım oldukça önemli;

  • O_RDONLY : Dosyayı sadece okuma için (read-only) açar.
  • O_WRONLY : Dosyayı sadece yazma için (write-only) açar. (Aşağıda yazma işlemlerinde kullanılacak)
  • O_RDWR : Dosyayı hem okuma hem de yazma için (read-write) açar.

Bu üç parametreden birisini mutlaka kullanılmalıdır. Bununla birlikte yukarıdakilere ilave olarak tercihen kullanabileceğimiz beş değişken daha vardır;

  • O_APPEND : Dosyaya yazma işlemi yaparken veriyi dosyanın en sonuna ekler.
  • O_CREATE : Dosyayı açarken eğer belirtilen isimde bir dosya yoksa oluşturur.
  • O_EXCL : O_CREATE ile birlikte kullanılır. Yeni dosyanın oluşturulabilmesi için belirtilen isimde bir dosyanın bulunmaması gerekir.
  • O_SYNC : Dosyanın synchronous I/O için açılmasını sağlar.
  • O_TRUNC : Dosya eğer zaten mevcutsa ve normal bir dosya ise 0 uzunlukta dosyayı keser (truncate)

Dosya izninden bahsedecek olursakta Linux’te olduğu gibi O_CREATE parametresi ile dosya mevcut değilse, yeni dosya oluştururken dosyaya izin değeri atabilirsiniz. İzinler hakkında detaylı bilgi için Tıklayınız.

2.3- Dosyayı Satır Satır Ekrana Yazdırma

Dosyayı seçtikten sonra tüm satırları tek tek seçmek ve ekrana yazmak isteyebiliriz. Bunun için aşağıdaki gibi bir kullanımı tercih edebiliriz. Tabi dosyanın üzerinde satır satır ilerlerken her satır ile ayrı ayrı oynayabilir ve işleme tabi tutabilirsiniz.

file, err := os.OpenFile("deneme.txt", os.O_RDONLY, 0755)
if err != nil {
    panic(err)
}

// Blok sonunda dosyayı kapat
defer file.Close()

// Satır satır oku
scanner := bufio.NewScanner(file)
for scanner.Scan() {
    satir := scanner.Text()
    fmt.Println(satir)
}

if err := scanner.Err(); err != nil {
    log.Fatal(err)
}

2.4- Dosya Meta Bilgilerine Ulaşmak

Seçtiğimiz bir dosyanın ismi, tarihi, boyutu gibi birçok meta özelliğine rahatlıkla erişebiliriz. Bunun için dosyayı açarken Open() veya OpenFile() methodlarını kullanabilirsiniz fakat en geniş meta özellikler için Stat() methodunu kullanarak dosyamızı seçeceğiz.

file, err := os.Stat("deneme.txt")
if err != nil {
    panic(err)
}

fmt.Println("Dosya Adı: ", file.Name())
fmt.Println("Dosya Boyutu: ", file.Size())
fmt.Println("Dosya İzni: ", file.Mode())
fmt.Println("Dosya Tarihi: ", file.ModTime())
fmt.Println("Dosya Klasör mü: ", file.IsDir())
fmt.Println("Dosya Kaynağı: ", file.Sys())

Bu programın çıktısına bakarsak;

Dosya Adı:  deneme.txt
Dosya Boyutu:  140     
Dosya İzni:  -rw-rw-rw-
Dosya Tarihi:  2020-09-03 13:53:54.5489958 +0300 +03
Dosya Klasör mü:  false
Dosya Kaynağı:  &{32 {3989454219 30844384} {3079957368 30844484} {2218824230 30835168} 0 140}

Edinebileceğimiz bilgileri bir listede toplayalım;

  • Name() string // Dosya ismini gösterir
  • Size() int64 // Byte olarak dosya boyutunu gösterir
  • Mode() FileMode // Dosya türünü gösterir
  • ModTime() time.Time // Dosyanın son düzenlenme tarihini gösterir
  • IsDir() bool // Dosyanın klasör olup olmadığını belirtir
  • Sys() interface{} // Dosya kaynağını gösterir

3- Dosyaya Yazma İşlemleri

Dosyalarımızı artık rahatça okuyabiliyoruz. Peki bu dosyalara istediğimiz verileri nasıl ekleyebiliriz? Bu sorunun cevabı da birazdan göreceğiniz gibi oldukça basit. Sadece dikkat etmeniz gereken tek nokta, dosyayı O_WRONLY kipiyle açtıktan sonra ek olarak hangi kipleri de kullanacağınızdır. İsterseniz hemen bu modlara bakıp örneklere geçelim.

  • O_RDONLY : Dosyayı sadece okuma için (read-only) açar. (Yukarıda okuma işlemlerinde kullandık)
  • O_WRONLY : Dosyayı sadece yazma için (write-only) açar.
  • O_RDWR : Dosyayı hem okuma hem de yazma için (read-write) açar.

Bu iki parametreden birisini mutlaka kullanılmalıdır. Bununla birlikte yukarıdakilere ilave olarak tercihen kullanabileceğimiz beş değişken daha vardır;

  • O_APPEND : Dosyaya yazma işlemi yaparken veriyi dosyanın en sonuna ekler.
  • O_CREATE : Dosyayı açarken eğer belirtilen isimde bir dosya yoksa oluşturur.
  • O_EXCL : O_CREATE ile birlikte kullanılır. Yeni dosyanın oluşturulabilmesi için belirtilen isimde bir dosyanın bulunmaması gerekir.
  • O_SYNC : Dosyanın synchronous I/O için açılmasını sağlar.
  • O_TRUNC : Dosya eğer zaten mevcutsa ve normal bir dosya ise 0 uzunlukta dosyayı keser (truncate)

Öyleyse küçük bir örnek yapalım.

file, err := os.OpenFile("deneme.txt", os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
if err != nil {
    log.Fatal(err)
}

// Fonksiyon sonunda dosyayı kapat
defer file.Close()

// Dosyaya yaz
len, err := file.WriteString("Merhaba, bu string dosyanın sonuna eklenecek")
if err != nil {
    log.Fatal(err)
} else {
    log.Println("Yazılan byte boyutu: " + strconv.Itoa(len))
}

Gördüğünüz gibi dosyaya yazma işleminde bulunmak işte bu kadar basit. Eğer yazdığınız değerden sonra alt satıra inmek isterseniz metninizin sonuna "\n" ekleyiniz.

4- Dosyaları Kapatmak

Dosyalar üzerinde çalışmalarımız bittikten sonra dosyayı serbest bırakabilmek için sonunda kapatmamız gerekir. Bunun için Close() fonksiyonunu kullanabiliriz.

file, err := os.Open("deneme.txt")
if err != nil {
    log.Fatal(err)
}

file.Close()

5- Dosyaları Silmek

Dosyalar üzerinde sayısız işlemler yapabiliyoruz. Bunlardan en sık kullanılanlarından birisi de dosyaları silebilmektir. Go ile dosya silme işlemi için Remove() ve RemoveAll() fonksiyonlarını kullanacağız.

  • Remove() : Belirtilen dosyayı siler
  • RemoveAll() : Bir dizin içindeki tüm dosyaları siler
err := os.Remove("deneme.txt") 
if err != nil { 
        log.Fatal(err) 
} 

err := os.RemoveAll("/home/user/test") 
if err != nil { 
        log.Fatal(err) 
}