предисловие
Чтение и запись ввода-вывода Golang предоставляет множество способов.В настоящее время я знаю библиотеку io, библиотеку os, библиотеку ioutil, библиотеку bufio, библиотеку байтов/строк и т. д.
Хотя Kudo — это хорошо, это означает больший выбор, но что меня смущает, так это то, какую библиотеку следует использовать в каком сценарии? Зачем?
Прежде чем сделать вывод, я хотел бы привести структуру проекта встроенной библиотеки ввода-вывода Golang, которая в основном предназначена для легкого понимания и использования:
# 只列举了核心的目录及文件
src:
- bufio
- bufio.go
- bytes
- buffer.go
- reader.go
- io
- ioutil
- ioutil.go
- io.go
- os
- file.go
- strings
- reader.go
1.io库
Он принадлежит базовой библиотеке определения интерфейса, и его роль заключается вОпределите некоторые основные интерфейсы и некоторые основные константы, и дайте описание функций этих интерфейсов.Обычные интерфейсы включают Reader, Writer и т.д. Как правило, эта библиотека используется только для вызова некоторых ее констант, таких какio.EOF
.
2.ioutil库
Входит в каталог io, его основная функцияв качестве инструментария, который имеет некоторые сравненияполезные функции, такие как ReadAll (чтение данных из источника), ReadFile (чтение содержимого файла), WriteFile (запись данных в файл), ReadDir (получение каталога)
3.os库
в основном сРабота с операционными системами, поэтому файловые операции в основном связаны с библиотекой ОС, например создание файла, открытие файла и т. д. Эта библиотека часто ассоциируется с библиотекой ioutil, библиотекой bufio и т. д.С использованием
4.bufio库
можно понимать какio库
Сверху добавляется слой инкапсуляции и добавляется функция кэширования. это может иioutil库
иbytes.Buffer
смущенный.
4.1 bufio VS ioutil
Библиотека: Оба обеспечивают функцию чтения и записи файлов, разница только в том, что bufio имеет дополнительный слой кэширования, это преимущество в основном проявляется при чтении больших файлов (ioutil.ReadFile — загружать содержимое в память за один раз, если содержимое слишком большое, легко разорвется память)
4.2 bufio VS bytes.Buffer
: Оба обеспечивают слой кэширования, их отличие в основном в том, что bufio нацелен нафайл в память, а bytes.Buffer дляпамять к памятиКэш (лично он немного похож на канал, вы также можете обнаружить, что bytes.Buffer не предоставляет интерфейс для записи данных в файл).
5.bytes和strings
Библиотеки: Эти две библиотеки немного сбивают с толку.Во-первых, они обе реализуют интерфейс Reader, поэтому их разница в основном вДругая цель, байты для байтов, а строки для строк (их методы очень похожи). Еще одно отличие состоит в том, что байты также имеют функцию буфера, а строки — нет.
Примечание: Что касается интерфейсов Reader и Writer, то его можно просто понимать как источник чтения и источник записи, то есть пока реализован метод Read в Reader, эта штука может использоваться как источник чтения, который может содержать данные и быть прочитаны нами, Writer То же самое верно.
Вышеизложенное является некоторыми из моих личных выводов. Вышеприведенные выводы будут объяснены ниже. Если есть какие-либо ошибки, пожалуйста, оставьте сообщение, чтобы исправить меня, сердце ❤️!
слежка за библиотекой io
В библиотеке io есть три часто используемых интерфейса, а именноReader
,Writer
иClose
.
// Read方法会接收一个字节数组p,并将读取到的数据存进该数组,最后返回读取的字节数n。
// 注意n不一定等于读取的数据长度,比如字节数组p的容量太小,n会等于数组的长度
type Reader interface {
Read(p []byte) (n int, err error)
}
// Write 方法同样接收一个字节数组p,并将接收的数据保存至文件或者标准输出等,返回的n表示写入的数据长度。
// 当n不等于len(p)时,返回一个错误。
type Writer interface {
Write(p []byte) (n int, err error)
}
// 关闭操作
type Closer interface {
Close() error
}
Конкретную реализацию метода Read можно увидеть в библиотеке строк:
// 定义一个Reader接口体
type Reader struct {
s string
i int64 // current reading index
prevRune int // index of previous rune; or < 0
}
// 通过NewReader方法得到 reader 对象,这里有个关键的地方是传入的字符串被赋值到 s 变量中
func NewReader(s string) *Reader {
return &Reader{s, 0, -1}
}
// Read方法: 核心是 copy 方法,参数b虽然是切片,但是copy方法会影响到它的底层数组
func (r *Reader) Read(b []byte) (n int, err error) {
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
r.prevRune = -1
// 核心方法
n = copy(b, r.s[r.i:])
r.i += int64(n)
return
}
слежение за библиотекой ioutil
Как упоминалось выше, библиотека ioutil представляет собой набор инструментов, который в основном содержит более практичные функции, такие как ReadFile, WriteFile и т. д. Единственное, что следует отметить, это то, что все они одноразового чтения и одноразовой записи, поэтому при чтенииОбратите внимание, что файл не должен быть слишком большим.
Чтение данных из файла:
func readByFile() {
data, err := ioutil.ReadFile( "./lab8_io/file/test.txt")
if err != nil {
log.Fatal("err:", err)
return
}
fmt.Println("data", string(data)) // hello world!
}
Записать данные в файл:
func writeFile() {
err := ioutil.WriteFile("./lab8_io/file/write_test.txt", []byte("hello world!"), 0644)
if err != nil {
panic(err)
return
}
}
Обход каталога. Об обходе каталога следует помнить, что он не сортируется естественным образом.
слежу за библиотекой bufio
Библиотека bufio также упоминалась выше. Она в основном добавляет слой функции кэширования к библиотеке io. Ниже приведен пример чтения больших файлов bufio:
func readBigFile(filePath string) error {
f, err := os.Open(filePath)
defer f.Close()
if err != nil {
log.Fatal(err)
return err
}
buf := bufio.NewReader(f)
count := 0
for {
count += 1
line, err := buf.ReadString('\n')
line = strings.TrimSpace(line)
if err != nil {
return err
}
fmt.Println("line", line)
// 这里是避免全部打印
if count > 100 {
break
}
}
return nil
}
Примечание:
1. ReadLine/ReadBytes/ReadString/ReadSlice из bufio: ReadString и ReadBytes эквивалентны, и ReadBytes, и ReadLine вызывают ReadSlice
Шпионить за библиотекой байтов/строк
Как упоминалось ранее, простая реализация интерфейса Reader, реализация базовых функций байтов и строк аналогична, вы можете проверить исходный код, чтобы убедиться:
// bytes/reader.go
// Read implements the io.Reader interface.
func (r *Reader) Read(b []byte) (n int, err error) {
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
r.prevRune = -1
n = copy(b, r.s[r.i:])
r.i += int64(n)
return
}
// strings/reader.go
func (r *Reader) Read(b []byte) (n int, err error) {
if r.i >= int64(len(r.s)) {
return 0, io.EOF
}
r.prevRune = -1
n = copy(b, r.s[r.i:])
r.i += int64(n)
return
}
Ссылка/рекомендация
Объясните принцип реализации пакета bufio в golang.
Две схемы чтения очень больших файлов в Golang
gist.GitHub.com/suntong/032…