1. İşletim Sistemi Kütüphanesinin Temelleri

Golang'daki os paketi, işletim sistemi işlevleri için platformdan bağımsız bir arayüz sağlar. Bir sonraki adımda, dosya açma, kapatma, okuma, yazma, dosya özniteliklerini elde etme ve ayarlama gibi işlemleri gerçekleştirmek için os paketini nasıl kullanacağımızı tartışacağız.

1.1 Dosya Açma ve Kapatma

Go dilinde, bir dosyayı açmak için os.Open işlevini kullanabilirsiniz. Bu işlev, bir *os.File nesnesi ve bir hata döndürecektir. Dosya açıldıktan sonra okuma, yazma ve diğer işlemleri gerçekleştirebilirsiniz. İşlemler tamamlandıktan sonra, dosyayı kapatmak ve ilgili kaynakları serbest bırakmak için file.Close çağrısını yapmalısınız.

İşte bir dosyanın açılmasının örneği:

package main

import (
    "fmt"
    "os"
)

func main() {
    // Mevcut dizindeki test.txt dosyasını aç
    file, err := os.Open("test.txt")
    if err != nil {
        // Dosya açma hatasıyla başa çık
        fmt.Println("Dosya açılırken hata oluştu:", err)
        return
    }
    // Dosyanın nihayetinde kapatılmasını sağlamak için defer deyimini kullan
    defer file.Close()

    // Dosya işlemleri...

    fmt.Println("Dosya başarıyla açıldı")
}

Yukarıdaki kodda, defer deyimini kullanarak file.Close'ın mutlaka çalıştırılmasını sağlıyoruz. Bu, Go dilinde kaynak temizliği için yaygın bir uygulamadır.

1.2 Dosya Okuma ve Yazma İşlemleri

os.File türü, dosya okuma ve yazma işlemleri için Read ve Write yöntemlerine sahiptir. Read yöntemi, verileri dosyadan bir byte dilimine okur, Write yöntemi ise bir byte diliminden dosyaya veri yazar.

Aşağıdaki örnek, bir dosyadan okuma ve bir dosyaya yazma işlemlerini nasıl gerçekleştireceğimizi göstermektedir:

package main

import (
    "fmt"
    "os"
)

func main() {
    // Dosyayı aç
    file, err := os.OpenFile("test.txt", os.O_RDWR, 0644)
    if err != nil {
        fmt.Println("Dosya açılırken hata oluştu:", err)
        return
    }
    defer file.Close()

    // Dosyaya içerik yaz
    mesaj := []byte("Merhaba, Gophers!")
    _, yazımHatasi := file.Write(mesaj)
    if yazımHatasi != nil {
        fmt.Println("Dosyaya yazılırken hata oluştu:", yazımHatasi)
        return
    }

    // Dosyayı başından oku
    file.Seek(0, 0)
    buffer := make([]byte, len(mesaj))
    _, okumaHatasi := file.Read(buffer)
    if okumaHatasi != nil {
        fmt.Println("Dosya okunurken hata oluştu:", okumaHatasi)
        return
    }

    fmt.Println("Dosya içeriği:", string(buffer))
}

Bu örnekte, os.Open yerine os.OpenFile'ı kullanıyoruz. os.OpenFile işlevi, dosyayı açarken kullanılacak modu ve izinleri belirtmenize olanak tanır. Yukarıdaki örnekte, os.O_RDWR bayrağı kullanılır, bu da dosyanın okuma-yazma modunda açılacağı anlamına gelir.

1.3 Dosya Özellikleri ve İzinler

Dosya durumu bilgilerine erişmek ve değiştirmek için os paketinden fonksiyonları kullanabilirsiniz. os.Stat veya os.Lstat kullanarak os.FileInfo arabirimini elde edebilirsiniz, bu da dosya hakkında boyut, izinler, değiştirme zamanı ve daha fazla bilgi sağlar.

İşte dosya durumunu elde etmenin bir örneği:

package main

import (
    "fmt"
    "os"
)

func main() {
    dosyaBilgisi, hata := os.Stat("test.txt")
    if hata != nil {
        fmt.Println("Dosya bilgileri alınırken hata oluştu:", hata)
        return
    }

    // Dosya boyutunu yazdır
    fmt.Printf("Dosya boyutu: %d byte\n", dosyaBilgisi.Size())

    // Dosya izinlerini yazdır
    fmt.Printf("Dosya izinleri: %s\n", dosyaBilgisi.Mode())
}

Dosya adını değiştirmek veya dosyanın izinlerini değiştirmeniz gerekiyorsa, dosyayı yeniden adlandırmak için os.Rename veya dosyanın izinlerini değiştirmek için os.Chmod kullanabilirsiniz.

package main

import (
    "fmt"
    "os"
)

func main() {
    // Dosya izinlerini salt okunur yap
    hata := os.Chmod("test.txt", 0444)
    if hata != nil {
        fmt.Println("Dosya izinleri değiştirilirken hata oluştu:", hata)
        return
    }

    // Dosyayı yeniden adlandır
    yenidenAdlandirmaHata := os.Rename("test.txt", "yenidenAdlandirilmis.txt")
    if yenidenAdlandirmaHata != nil {
        fmt.Println("Dosya yeniden adlandırılırken hata oluştu:", yenidenAdlandirmaHata)
        return
    
    }

    fmt.Println("Dosya işlemleri başarılı")
}

Burada, test.txt dosyasının izinlerini salt okunur yapar ve ardından dosyayı yenidenAdlandirilmis.txt olarak yeniden adlandırırız. Dosya izinlerini değiştirirken, yanlış izin ayarları erişilemeyen dosyalara yol açabileceği için dikkatli olun.

2. IO Kütüphanesinin Temel Kullanımı

Go dilinde io kütüphanesi, temel giriş/çıkış (I/O) işlemleri için temel arabirimler sağlar. io kütüphanesinin tasarımı basitlik ve düzenli arabirim prensiplerini takip eder, farklı türdeki I/O işlemleri için dosya okuma/yazma, ağ iletişimi, veri önbelleği ve daha fazlası için temel desteği sağlar.

2.2 Okuyucu ve Yazıcı Arabirimlerinin Kullanımı

io.Reader ve io.Writer, bir nesnenin okuma ve yazma işlemlerini belirtmek için kullanılan temel arabirimlerdir. Dosyalar, ağ bağlantıları ve önbellek gibi farklı türler tarafından uygulanırlar.

io.Reader

io.Reader arabirimine ait Read yöntemi bulunmaktadır:

Read(p []byte) (n int, err error)

Bu yöntem, io.Reader içinden p'ye kadar olan veriyi p'ye kadar okur. Okunan bayt sayısını n (0 <= n <= len(p)) ve karşılaşılan herhangi bir hatayı döndürür.

Örnek kod:

package main

import (
    "fmt"
    "io"
    "strings"
)

func main() {
    r := strings.NewReader("Merhaba, Dünya!")

    buf := make([]byte, 4)
    for {
        n, hata := r.Read(buf)
        if hata == io.EOF {
            break
        }
        fmt.Printf("Okunan baytlar: %d, İçerik: %s\n", n, buf[:n])
    }
}

Bu örnekte, bir string'den veri okumak için strings.NewReader oluşturuyor ve ardından veriyi 4 baytlik parçalar halinde okuyoruz.

io.Writer

io.Writer arabirimi, Write yöntemine sahiptir:

Write(p []byte) (n int, err error)

Bu yöntem, p'den gelen veriyi altta yatan veri akışına yazar ve yazılan bayt sayısını ve karşılaşılan herhangi bir hatayı döndürür.

Örnek kod:

package main

import (
    "fmt"
    "os"
)

func main() {
    data := []byte("Merhaba, Dünya!\n")
    n, hata := os.Stdout.Write(data)
    if hata != nil {
        panic(hata)
    }
    fmt.Printf("Yazılan baytlar: %d\n", n)
}

Bu örnek, basit bir metni standart çıkış os.Stdout'a yazarak, io.Writer'ın bir uygulaması olarak hareket eder.

2.3 Gelişmiş Okuma/Yazma Fonksiyonları

io paketi, veri kopyalama ve belirli miktarda veri okuma gibi yaygın görevleri kolaylaştırabilen bazı gelişmiş fonksiyonlar sağlar.

Kopyalama Fonksiyonu

io.Copy, ara belleğe gerek olmadan bir io.Reader dan bir io.Writer a direkt olarak veri kopyalamak için kullanışlı bir yöntemdir.

Örnek kod:

package main

import (
    "io"
    "os"
    "strings"
)

func main() {
    r := strings.NewReader("Basit kopyalama işlemi örneği")
    _, err := io.Copy(os.Stdout, r)
    if err != nil {
        panic(err)
    }
}

Bu örnekte bir string'i doğrudan standart çıktıya kopyalıyoruz.

ReadAtLeast Fonksiyonu

io.ReadAtLeast fonksiyonu, belirtilen miktarda verinin dönmeden önce bir io.Reader dan en az o miktarda verinin okunmasını sağlar.

func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)

Örnek kod:

package main

import (
    "fmt"
    "io"
    "strings"
)

func main() {
    r := strings.NewReader("Go Dilindeki Türkçe Websitesi")
    buf := make([]byte, 14)
    n, err := io.ReadAtLeast(r, buf, 14)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Printf("%s\n", buf[:n])
}

Bu örnekte io.ReadAtLeast, buf içine en az 14 byte veri okumayı denemektedir.

Bu gelişmiş okuma/yazma fonksiyonları, I/O ile ilgili görevleri daha verimli bir şekilde ele almanızı sağlar ve daha karmaşık program mantığının temelini oluşturmak için sağlam bir temel sunar.