1. Podstawy biblioteki OS
Pakiet os
w Golang zapewnia platformowo niezależny interfejs do funkcji systemu operacyjnego. Następnie omówimy, jak korzystać z pakietu os
do obsługi otwierania, zamykania, czytania, zapisywania plików, a także uzyskiwania i ustawiania atrybutów plików.
1.1 Otwieranie i Zamykanie Plików
W języku Go można użyć funkcji os.Open
, aby otworzyć plik, która zwróci obiekt *os.File
oraz błąd. Po otwarciu pliku można wykonywać operacje odczytu, zapisu i inne. Po zakończeniu operacji należy wywołać file.Close
, aby zamknąć plik i zwolnić odpowiadające zasoby.
Poniżej znajduje się przykład otwarcia pliku:
package main
import (
"fmt"
"os"
)
func main() {
// Otwórz plik test.txt w bieżącym katalogu
file, err := os.Open("test.txt")
if err != nil {
// Obsłuż błąd otwierania pliku
fmt.Println("Błąd podczas otwierania pliku:", err)
return
}
// Użyj instrukcji defer, aby zapewnić, że plik zostanie ostatecznie zamknięty
defer file.Close()
// Operacje na pliku...
fmt.Println("Plik został pomyślnie otwarty")
}
W powyższym kodzie używamy instrukcji defer
, aby zapewnić, że file.Close
zostanie wykonane niezależnie od tego, co się stanie. To jest powszechna praktyka w języku Go do czyszczenia zasobów.
1.2 Operacje Odczytu i Zapisu Pliku
Typ os.File
posiada metody Read
i Write
, które można użyć do operacji odczytu i zapisu pliku. Metoda Read
odczytuje dane z pliku do wycinka bajtów, a metoda Write
zapisuje dane z wycinka bajtów do pliku.
Poniższy przykład demonstruje, jak czytać i zapisywać do pliku:
package main
import (
"fmt"
"os"
)
func main() {
// Otwórz plik
file, err := os.OpenFile("test.txt", os.O_RDWR, 0644)
if err != nil {
fmt.Println("Błąd podczas otwierania pliku:", err)
return
}
defer file.Close()
// Zapisz zawartość pliku
message := []byte("Witaj, Gopherzy!")
_, writeErr := file.Write(message)
if writeErr != nil {
fmt.Println("Błąd podczas zapisywania do pliku:", writeErr)
return
}
// Odczytaj plik od początku
file.Seek(0, 0)
buffer := make([]byte, len(message))
_, readErr := file.Read(buffer)
if readErr != nil {
fmt.Println("Błąd odczytu pliku:", readErr)
return
}
fmt.Println("Zawartość pliku:", string(buffer))
}
W tym przykładzie używamy os.OpenFile
zamiast os.Open
. Funkcja os.OpenFile
pozwala określić tryb i uprawnienia do użycia podczas otwierania pliku. W powyższym przykładzie użyto flagi os.O_RDWR
, co oznacza, że plik zostanie otwarty w trybie odczytu i zapisu.
1.3 Właściwości plików i uprawnienia
Możesz użyć funkcji z pakietu os
, aby uzyskać dostęp do informacji o statusie pliku i je modyfikować. Użyj os.Stat
lub os.Lstat
, aby uzyskać interfejs os.FileInfo
, który dostarcza informacje o pliku, takie jak rozmiar, uprawnienia, czas modyfikacji i inne.
Oto przykład, jak uzyskać status pliku:
package main
import (
"fmt"
"os"
)
func main() {
fileInfo, err := os.Stat("test.txt")
if err != nil {
fmt.Println("Błąd podczas pobierania informacji o pliku:", err)
return
}
// Wyświetl rozmiar pliku
fmt.Printf("Rozmiar pliku: %d bajtów\n", fileInfo.Size())
// Wyświetl uprawnienia pliku
fmt.Printf("Uprawnienia pliku: %s\n", fileInfo.Mode())
}
Jeśli chcesz zmienić nazwę pliku lub modyfikować jego uprawnienia, możesz użyć os.Rename
do zmiany nazwy pliku lub os.Chmod
do zmiany uprawnień pliku.
package main
import (
"fmt"
"os"
)
func main() {
// Zmień uprawnienia pliku na tylko do odczytu
err := os.Chmod("test.txt", 0444)
if err != nil {
fmt.Println("Błąd podczas zmiany uprawnień pliku:", err)
return
}
// Zmień nazwę pliku
renameErr := os.Rename("test.txt", "zmieniona-nazwa.txt")
if renameErr != nil {
fmt.Println("Błąd podczas zmiany nazwy pliku:", renameErr)
return
}
fmt.Println("Operacje na pliku zakończone pomyślnie")
}
Tutaj zmieniamy uprawnienia pliku test.txt
na tylko do odczytu, a następnie zmieniamy nazwę pliku na zmieniona-nazwa.txt
. Zauważ, że podczas modyfikacji uprawnień pliku należy zachować ostrożność, ponieważ niewłaściwe ustawienia uprawnień mogą prowadzić do niedostępnych plików.
2. Podstawowe użycie biblioteki IO
W języku Go biblioteka io
dostarcza podstawowe interfejsy dla podstawowych operacji wejścia/wyjścia (I/O). Projektowanie biblioteki io
kieruje się zasadami prostoty i jednolitymi interfejsami, zapewniając podstawowe wsparcie dla różnych rodzajów operacji wejścia/wyjścia, takich jak odczyt/zapis plików, komunikacja sieciowa, buforowanie danych i wiele więcej.
2.2 Korzystanie z interfejsów Reader i Writer
io.Reader
i io.Writer
to dwa podstawowe interfejsy używane do określenia operacji odczytu i zapisu obiektu. Są one implementowane przez różne typy, takie jak pliki, połączenia sieciowe i bufory.
io.Reader
Interfejs io.Reader
posiada metodę Read:
Read(p []byte) (n int, err error)
Ta metoda czyta do len(p)
bajtów danych z io.Reader
do p
. Zwraca liczbę odczytanych bajtów n
(0 <= n
<= len(p
)) oraz napotkany błąd.
Przykładowy kod:
package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("Witaj, świecie!")
buf := make([]byte, 4)
for {
n, err := r.Read(buf)
if err == io.EOF {
break
}
fmt.Printf("Odczytane bajty: %d, Zawartość: %s\n", n, buf[:n])
}
}
W tym przykładzie tworzymy strings.NewReader
, aby odczytać dane z ciągu znaków, a następnie czytamy dane porcjami po 4 bajty.
io.Writer
Interfejs io.Writer
posiada metodę Write:
Write(p []byte) (n int, err error)
Ta metoda zapisuje dane z p
do strumienia danych podstawowego, zwracając liczbę zapisanych bajtów oraz napotkany błąd.
Przykładowy kod:
package main
import (
"fmt"
"os"
)
func main() {
data := []byte("Witaj, świecie!\n")
n, err := os.Stdout.Write(data)
if err != nil {
panic(err)
}
fmt.Printf("Zapisane bajty: %d\n", n)
}
Ten przykład zapisuje prosty ciąg znaków do standardowego wyjścia os.Stdout
, które działa jako implementacja io.Writer
.
2.3 Zaawansowane funkcje odczytu/zapisu
Pakiet io
udostępnia kilka zaawansowanych funkcji, które mogą uprościć powszechne zadania, takie jak kopiowanie danych i odczytywanie określonej ilości danych.
Funkcja Kopiowania
io.Copy
to wygodna metoda bezpośredniego kopiowania danych z io.Reader
do io.Writer
bez potrzeby pośredniego buforowania.
Przykładowy kod:
package main
import (
"io"
"os"
"strings"
)
func main() {
r := strings.NewReader("Przykład prostego kopiowania")
_, err := io.Copy(os.Stdout, r)
if err != nil {
panic(err)
}
}
W tym przykładzie bezpośrednio kopiujemy ciąg znaków na standardowe wyjście.
Funkcja ReadAtLeast
Funkcja io.ReadAtLeast
służy do zapewnienia, że z io.Reader
zostanie odczytana co najmniej określona ilość danych przed zwróceniem wyniku.
func ReadAtLeast(r Reader, buf []byte, min int) (n int, err error)
Przykładowy kod:
package main
import (
"fmt"
"io"
"strings"
)
func main() {
r := strings.NewReader("Strona Chińskiego Języka Go")
buf := make([]byte, 14)
n, err := io.ReadAtLeast(r, buf, 14)
if err != nil {
fmt.Println(err)
}
fmt.Printf("%s\n", buf[:n])
}
W tym przykładzie io.ReadAtLeast
próbuje odczytać co najmniej 14 bajtów danych do buf
.
Te zaawansowane funkcje odczytu/zapisu pozwalają efektywniej obsługiwać zadania związane z wejściem/wyjściem i stanowią solidną podstawę do budowania bardziej złożonej logiki programu.