Go Guide 10 - Расскажите о путанице в чтении и записи Golang IO

Go

предисловие

Чтение и запись ввода-вывода 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…