Intrare-ieșire cu buffer
Majoritatea operațiunilor încorporate de citire și scriere nu utilizează buffer. Acest lucru poate avea un impact negativ asupra performanței aplicației. Pentru a bufferiza fluxurile de citire și scriere, Go oferă o serie de funcționalități, care sunt concentrate în pachetul bufio.
Scrierea prin buffer
Pentru a scrie într-o sursă de date prin buffer, în pachetul bufio este definit tipul Writer. Pentru a scrie date, se poate folosi una dintre metodele sale:
func (b *Writer) Write(p []byte) (nn int, err error)
func (b *Writer) WriteByte(c byte) error
func (b *Writer) WriteRune(r rune) (size int, err error)
func (b *Writer) WriteString(s string) (int, error)
- Write(): scrie un slice de octeți
- WriteByte(): scrie un singur octet
- WriteRune(): scrie un obiect de tip rune
- WriteString(): scrie un șir de caractere
Când aceste metode sunt executate, datele se acumulează mai întâi în buffer, iar pentru a le descărca în sursa de date, trebuie să apelăm metoda Flush().
Pentru a crea un flux de ieșire prin buffer, se folosește funcția bufio.NewWriter():
func NewWriter(w io.Writer) *Writer
Aceasta primește un obiect io.Writer - acesta poate fi orice obiect în care se scrie: os.Stdout, fișier, etc. Ca rezultat, funcția returnează un obiect de tip bufio.Writer:
package main
import (
"fmt"
"os"
"bufio"
)
func main() {
rows := []string{
"Hello Go!",
"Welcome to Golang",
}
file, err := os.Create("some.dat")
writer := bufio.NewWriter(file)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer file.Close()
for _, row := range rows {
writer.WriteString(row) // scrierea șirului
writer.WriteString("\n") // caracter de sfârșit de linie
}
writer.Flush() // descărcăm datele din buffer în fișier
}
În acest caz, două șiruri sunt scrise într-un fișier printr-un flux de ieșire cu buffer.
Citirea prin buffer
Pentru a citi dintr-o sursă de date prin buffer, în pachetul bufio este definit tipul Reader. Pentru a citi date, se poate folosi una dintre metodele sale:
func (b *Reader) Read(p []byte) (n int, err error)
func (b *Reader) ReadByte() (byte, error)
func (b *Reader) ReadBytes(delim byte) ([]byte, error)
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error)
func (b *Reader) ReadRune() (r rune, size int, err error)
func (b *Reader) ReadSlice(delim byte) (line []byte, err error)
func (b *Reader) ReadString(delim byte) (string, error)
- Read(p []byte): citește un slice de octeți și returnează numărul de octeți citiți
- ReadByte(): citește un singur octet
- ReadBytes(delim byte): citește un slice de octeți din flux până când întâlnește octetul delim
- ReadLine(): citește un șir de caractere ca slice de octeți
- ReadRune(): citește un obiect de tip rune
- ReadSlice(delim byte): citește un slice de octeți din flux până când întâlnește octetul delim
- ReadString(delim byte): citește un șir de caractere până când întâlnește octetul delim
Pentru a crea un flux de intrare prin buffer, se folosește funcția bufio.NewReader():
func NewReader(rd io.Reader) *Reader
Aceasta primește un obiect io.Reader - acesta poate fi orice obiect din care se citește: os.Stdin, fișier, etc. Ca rezultat, funcția returnează un obiect bufio.Reader:
package main
import (
"fmt"
"os"
"bufio"
"io"
)
func main(){
file, err := os.Open("some.data")
if err != nil {
fmt.Println("Nu s-a putut deschide fișierul:", err)
return
}
defer file.Close()
reader := bufio.NewReader(file)
for {
line, err := reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
} else {
fmt.Println(err)
return
}
}
fmt.Print(line)
}
}
În acest caz, datele sunt citite dintr-un fișier anterior scris. Pentru aceasta, obiectul fișierului os.File este transmis funcției bufio.NewReader, iar pe baza acestuia se creează un obiect bufio.Reader. Deoarece citirea se face pe linii, fiecare linie este citită din flux până când se întâlnește caracterul de sfârșit de linie \n.