Menu

Golang Dosya Okuma ve Yazma: os, bufio ve Dizinler

Go'da dosya okumak ve yazmak: os.ReadFile ve os.WriteFile, bufio.Scanner ile satır satır okumak, os.OpenFile ile sona eklemek, bir dosyanın var olup olmadığını kontrol etmek ve dizinlerle çalışmak.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

Bütün bir dosyayı okumak ve yazmak

os.WriteFile ve os.ReadFile çoğu ihtiyacı karşılar. Tek bir çağrıda açar, yazar ya da okur ve kapatırlar.

Bu sayfadaki örnekler os.MkdirTemp'ten gelen geçici bir dizinde çalışır ve onu defer os.RemoveAll(dir) ile kaldırır, böylece geride hiçbir şey bırakmazlar. Kendi kodunuzda "config.json" gibi göreli bir yol, sürecin çalışma dizinine göre çözülür; bu da mutlaka kaynak dosyanın ya da binary'nin dizini değildir.

os.WriteFile gerekirse dosyayı oluşturur ve varsa onu sıfırlar (truncate). Üçüncü argüman yeni oluşturulan bir dosya için Unix iznidir: 0o644, sahibinin okuyup yazabileceği, diğer herkesin okuyabileceği anlamına gelir. Zaten var olan bir dosya için yok sayılır ve süreç umask'ı bazı bitleri kaldırabilir.

os.ReadFile her şeyi belleğe okur. Bu yapılandırma dosyaları ve küçük girdiler için doğrudur, çok gigabaytlık bir log için yanlıştır.

bufio.Scanner ile satır satır okumak

Büyük dosyalar için ya da zaten satırları istediğinizde bufio.Scanner kullanın. Parçalar halinde okur ve size her seferinde yeni satır karakteri olmadan bir satır verir.

Üç ayrıntı:

  • Döngüden sonra sc.Err()'ü kontrol edin. Scan hem dosya sonunda hem de bir hatada false döndürür ve yalnızca Err onları ayırt eder.
  • 64 KB satır sınırı. Varsayılan olarak 64 KB'tan uzun tek bir satır scanner'ı bufio.Scanner: token too long ile durdurur. Uzun satırlı dosyalar (küçültülmüş JSON, bazı loglar) için döngüden önce sınırı yükseltin: sc.Buffer(make([]byte, 1024*1024), 10*1024*1024).
  • Diğer birimler. sc.Split(bufio.ScanWords) kelimeler verir; bufio.ScanRunes karakterler verir.

Bir akışı satırlar yerine sabit boyutlu parçalar halinde okumak için bir döngüde f.Read(buf) kullanın ya da başka bir writer'a io.Copy yapın.

Yazmak: os.Create, os.OpenFile ve sona ekleme

os.Create(name) bir dosyayı yazmak için açar; oluşturur ya da sıfırlar. os.OpenFile bayraklar üzerinden tam kontrol verir:

BayrakAnlamı
os.O_RDONLY, os.O_WRONLY, os.O_RDWRokumak, yazmak ya da ikisi için aç (birini seçin)
os.O_CREATEdosya yoksa oluştur
os.O_TRUNCaçarken dosyayı boşalt
os.O_APPENDher yazma sona gider
os.O_EXCLO_CREATE ile: dosya zaten varsa başarısız ol

os.Open(name), OpenFile(name, O_RDONLY, 0)'dır. os.Create(name), OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0o666)'dır.

Yazarken Close'tan gelen hata önemlidir. Bazı dosya sistemleri yazma hatalarını yalnızca kapatma anında bildirir, bu yüzden tek başına defer f.Close() kaybolan veriyi gizleyebilir. Yazdığınız dosyalar için appendLine'ın yaptığı gibi Close'u açıkça kontrol edin. Yalnızca okuduğunuz dosyalar için defer f.Close() yeterlidir.

fmt.Fprintln ve fmt yazdırma fonksiyonlarının geri kalanı, bir dosya dahil her io.Writer'ı kabul eder. Bir bufio.Writer küçük yazmaları bellekte toplar. w.Flush()'ı unutmak klasik bir hatadır: program normal biçimde çıkar ve son birkaç kilobayt dosyaya hiç ulaşmaz.

Dosya var mı?

Go'da os.Exists yoktur. os.Stat'ı çağırın ve hatayı inceleyin:

errors.Is(err, fs.ErrNotExist) güncel kalıptır. Sarmalanmış hataların içini göremeyen eski os.IsNotExist(err)'ün yerini alır.

Açmadan önce kontrol etmek çoğu zaman gereksizdir ve race'e açıktır: dosya kontrol ile açma arasında ortaya çıkabilir ya da kaybolabilir. Genellikle onu doğrudan açıp açmadan gelen fs.ErrNotExist'i ele alırsınız. Bir dosyayı yalnızca henüz yoksa oluşturmak için, kontrolü ve oluşturmayı tek bir atomik adım yapan O_CREATE|O_EXCL'i kullanın.

Dizinler

GörevFonksiyon
tek bir dizin oluşturmakos.Mkdir(path, 0o755)
ebeveynleriyle bir yol oluşturmakos.MkdirAll(path, 0o755)
bir dizini listelemekos.ReadDir(path)
bir ağacı dolaşmakfilepath.WalkDir(root, fn)
bir dosyayı ya da boş dizini silmekos.Remove(path)
bir ağacı silmekos.RemoveAll(path)
yeniden adlandırmak ya da taşımakos.Rename(old, new)
geçici dosya ya da dizinos.CreateTemp("", "prefix-*"), os.MkdirTemp("", "prefix")
yol parçalarını birleştirmekfilepath.Join(a, b, c)

Dosya sistemi yolları için path/filepath kullanın: işletim sistemi için doğru ayırıcıyı kullanır (Windows'ta \). path paketi ise URL'ler gibi eğik çizgiyle ayrılmış yollar içindir.

Go 1.24 ayrıca dosyaları yalnızca tek bir dizinin içinde açan ve .. ya da symlink'lerle dışarı kaçan yolları reddeden os.Root'u (os.OpenRoot(dir)) ekledi. Dosya adları kullanıcılardan geldiğinde onu kullanın.

Sık yapılan hatalar

  • Hataları kontrol etmemek. Bu çağrıların her biri başarısız olabilir. Açılamayan bir dosya nil'dir ve üzerindeki sonraki her Read, Write ya da Close invalid argument döndürür; bu da asıl nedeni (dosya yoktu ya da izin reddedildi) gizler.
  • Bir tarama döngüsünden sonra sc.Err()'ü unutmak. Bir okuma hatası dosya sonu gibi görünür.
  • Bir bufio.Writer üzerinde Flush'ı unutmak. Dosyanın sonu eksik kalır.
  • Yazdıktan sonra Close'tan gelen hatayı yok saymak. Yazma hataları yalnızca orada ortaya çıkabilir.
  • Birçok dosya üzerinde dönen bir döngü içinde defer f.Close(). Dosyalar fonksiyon dönene kadar açık kalır ve dosya tanımlayıcılarınız tükenebilir. Gövdeyi bir fonksiyona taşıyın ki her dosya yinelemede kapansın.
  • Onluk olarak yazılmış izinler. 644, 0o644 değildir. Go 644'ü onluk sayı olarak okur; bu da 0o1204'tür ve tuhaf bitler ayarlar.

Sıkça Sorulan Sorular

Go'da bir dosyanın tamamı bir string'e nasıl okunur?

data, err := os.ReadFile("notes.txt") içeriği []byte olarak döndürür; string(data) ile dönüştürün. Dosyayı sizin yerinize açar, okur ve kapatır. Belleğe rahatça sığan dosyalar için kullanın; büyük dosyalar için bufio.Scanner ile satır satır okuyun.

Go'da bir dosya satır satır nasıl okunur?

Dosyayı os.Open ile açın, defer f.Close() yazın, onu bufio.NewScanner(f) ile sarın, for sc.Scan() { line := sc.Text() } ile dönün ve döngüden sonra sc.Err()'ü kontrol edin. 64 KB'tan uzun satırlar, tamponu sc.Buffer ile büyütmedikçe scanner'ın token too long ile başarısız olmasına yol açar.

Go'da bir dosyanın sonuna nasıl ekleme yapılır?

Onu os.OpenFile(name, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) ile açın, yazın ve Close'tan gelen hatayı kontrol edin. O_CREATE dosya yoksa oluşturur, O_APPEND her yazmanın sona gitmesini sağlar.

Go'da bir dosyanın var olup olmadığı nasıl kontrol edilir?

os.Stat(path)'i çağırın ve hatayı errors.Is(err, fs.ErrNotExist) ile test edin. Nil bir hata dosyanın var olduğu anlamına gelir. Başka herhangi bir hata (örneğin permission denied) bunu bilemeyeceğiniz anlamına gelir, bu yüzden onu "yok" olarak ele almak yerine ayrıca işleyin.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA