Писането във файлове и четенето от тях са прости задачи, нужни в много програми. Първо ще разгледаме някои примери за четене от файлове.
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
)
Четенето от файл изисква проверка за грешка почти при всяко извикване на функция. Този помощник ще опрости проверките.
func check(e error) {
if e != nil {
panic(e)
}
}
func main() {
Може би най-простата задача е изчитането на цялото съдържание от файла в паметта наведнъж.
пѫтека := filepath.Join(os.TempDir(), "dat")
dat, err := os.ReadFile(пѫтека)
check(err)
fmt.Print(string(dat))
Често ще ви се налага да управлявате начина и да избирате кои части от
файла да бъдат прочетени. В тези случаи използвайте първо
os.Open(пѫтека). Тази функция връща стойности от видовете (*os.File,
error).
f, err := os.Open(пѫтека)
check(err)
Прочитаме няколко байта1 от началото на файла. Разрешаваме да бъдат прочетени 6, но забележете също колко всъщност са прочетени.(бел. прев. какво иска да каже авторът с „но заб…”???) За добавяне като глава обяснение след примера: http://www.tcpipguide.com/free/t_BinaryInformationandRepresentationBitsBytesNibbles.htm
byte наистина означава хапка защото понятието е просто написана по различен начин думата bite, за да няма объркване с въведеното вече понятие за най-малката възможна единица данни bit. Виж https://en.wikipedia.org/wiki/Byte#citenote-Buchholz1977-14 b1 := make([]byte, 6)
n1, err := f.Read(b1)
check(err)
fmt.Printf("%d хапки: %s\n", n1, string(b1[:n1]))
Също така можете да „скочите” със Seek до познато място във файла и да
четете с Read оттам нататък.
o2, err := f.Seek(6, io.SeekStart)
check(err)
Прочитаме новия ред и два байта – общо три.
b2 := make([]byte, 3)
n2, err := f.Read(b2)
check(err)
fmt.Printf("%d хапки @ %d: ", n2, o2)
fmt.Printf("%v\n", string(b2[:n2]))
Други начини за търсене във файл са чрез отнасяне към текущото място на показалеца.
_, err = f.Seek(2, io.SeekCurrent)
check(err)
и отнесено към края на файла
_, err = f.Seek(-4, io.SeekEnd)
check(err)
Пакетът io предоставя някои полезни за четене на файлове функции.
Например четения като горните могат да бъдат осъществени по-мощно с
помощта на ReadAtLeast.
o3, err := f.Seek(6, io.SeekStart)
check(err)
b3 := make([]byte, 3)
n3, err := io.ReadAtLeast(f, b3, 3)
check(err)
fmt.Printf("%d хапки @ %d: %s\n", n3, o3, string(b3))
Няма готова функция за връщане в началото но Seek(0, io.SeekStart)
върши точно това.
_, err = f.Seek(0, io.SeekStart)
check(err)
Пакетът bufio осъществява складиращ четец, който може да ни е от полза
както заради производителността си така и за това, че предоставя
допълнителни методи за четене.
r4 := bufio.NewReader(f)
b4, err := r4.Peek(9)
check(err)
fmt.Printf("9 хапки: %s\n", string(b4))
Затваряме файла, като сме готови. Обикновено това действие бива насрочено
веднага след извикването на Open(…) с помощта на defer.
f.Close()
}
Важно! За да работят примерите, трябва пѫтят, описан чрез пѫтека да сочи до
съществуващ файл, така че създайте го, например така:
$ echo "ала" > /tmp/dat
$ echo "баланица" >> /tmp/dat
Забележете, че внимаваме колко байта ще прочетем, защото българските букви, поради местонахожденията си в таблицата УНИКОД, чиито номера не могат да се вместят в един байт, са представени в UTF-8 чрез двубайтови последователности. Иначе просто ще имаме счупени букви. Проверете като промените броя байтове при някои четения..
$ go run reading-files.go
ала
баланица
6 хапки: ала
3 хапки @ 6:
б
3 хапки @ 6:
б
9 хапки: ала
б
А сега ще разгледаме писането във файлове.
Следващ пример: Писане във файлове.