В области компьютерных и информационных технологий I/Oэтот термин означает ввод/вывод (англ. Input/Output), обычно относится к вводу и выводу данных между памятью (внутренней и внешней) или другими периферийными устройствами, представляет собой систему обработки информации и внешняя связь. Входы — это сигналы или данные, полученные системой, а выходы — это сигналы или данные, отправленные из нее.

I/OВ языке Go существует множество встроенных библиотек , задействованных в операциях , таких как: ioбиблиотека, osбиблиотека, ioutilбиблиотека, bufioбиблиотека, bytesбиблиотека , библиотека и stringsт. д. Хорошо иметь так много встроенных библиотек, но I/Oкакую библиотеку мы должны выбрать, когда речь идет о задействованных сценариях?

io.Чтение/Писатель

Язык Go использует io.Readerи io.Writerдва интерфейса для абстракции I/O, их определения следующие.

type Reader interface {
 Read(p []byte) (n int, err error)
}

type Writer interface {
 Write(p []byte) (n int, err error)
}

io.ReaderИнтерфейс представляет объект, из которого можно прочитать поток байтов, и объект, в который io.Writerможно записать поток байтов.

Несколько часто используемых реализаций io.Reader/Writer

  • net.Conn: представляет сетевое подключение.
  • os.Stdin, os.Stdout, os.Stderr: стандартный ввод, вывод и ошибка.
  • os.File: сеть, стандартный ввод и вывод, потоковое чтение файлов.
  • strings.Reader: строки абстрагируются в реализацию io.Reader.
  • bytes.Reader: []byte абстрагируется от реализации io.Reader.
  • bytes.Buffer: []byte абстрагируется от реализации io.Reader и io.Writer.
  • bufio.Reader/Writer: Чтение и запись буферизованного потока (например, построчно).

В дополнение к этим реализациям ioutilбиблиотека инструментов содержит множество функций инструментов ввода-вывода, а встроенная библиотека, связанная с кодированием encoding/base64и т. д., encoding/binaryтакже реализует соответствующие функции кодирования через io.Reader и io.Writer.

Связь между этими общими реализациями и библиотеками инструментов и io.Reader и io.Writer может быть представлена ​​на следующей диаграмме.

картина

Сценарии использования для каждой библиотеки ввода/вывода

io библиотека

ioБиблиотеки принадлежат базовой библиотеке определения интерфейса. Его основная функция состоит в том, чтобы определять I/Oосновные интерфейсы и основные константы, а также объяснять функции этих интерфейсов. При написании кода для выполнения I/Oопераций эта библиотека обычно используется только для вызова ее констант и определений интерфейса, например, для определения того, был io.EOFли он прочитан, и для использования io.Readerее в качестве объявления типа переменных.

// 字节流读取完后,会返回io.EOF这个error
for {
 n, err := r.Read(buf)
 fmt.Println(n, err, buf[:n])
 if err == io.EOF {
  break
 }
}

библиотека ОС

osБиблиотека в основном занимается работой операционной системы и действует как мост для взаимодействия между программой Go и операционной системой. Операции по созданию файлов, открытию или закрытию файлов, сокетов и т. д. связаны с операционной системой, поэтому все они osвыполняются через библиотеки. Эта библиотека часто используется вместе с ioutil, bufioи т.д.

библиотека ioutil

ioutilБиблиотека представляет собой набор инструментов, который предоставляет множество полезных функций инструмента ввода-вывода, таких как ReadAll, ReadFile, WriteFile, ReadDir. Единственное, что следует отметить, это то, что все они одноразового чтения и одноразовой записи, поэтому при его использовании необходимо обращать внимание на размер файла, особенно при одновременном чтении данных из файла в память.

Прочитать все в файле

func readByFile() {
  data, err := ioutil.ReadFile( "./file/test.txt")
  if err != nil {
    log.Fatal("err:", err)
    return
  }
  fmt.Println("data"string(data)) 
}

Записать данные в файл сразу

func writeFile() {
  err := ioutil.WriteFile("./file/write_test.txt", []byte("hello world!"), 0644)
  if err != nil {
    panic(err)
    return
  }
}

библиотека буфио

bufio, который можно понимать как ioдополнительный слой кэша на базе библиотеки, предоставляет множество функций для чтения и записи построчно, от побайтового чтения и записи в библиотеке io до построчного чтения и записи .Для написания кода все же намного удобнее.


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
  // 循环中打印前100行内容
  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
}
  • Методы ReadLine и ReadString: buf.ReadLine(), buf.ReadString("\n") читаются построчно, но ReadLine считывает []byte, который считывает строку напрямую, и, наконец, они вызывают нижний слой. Оба метода являются ReadSlice .
  • Библиотека bufio VS ioutil: библиотеки bufio и ioutil обеспечивают возможность чтения и записи файлов. Единственная разница между ними в том, что у bufio есть дополнительный уровень кэширования. Это преимущество в основном проявляется при чтении больших файлов.

библиотека байтов и строк

Bytes.Reader и string.Reader в библиотеках bytes и strings реализуют io.Readerинтерфейс, а также предоставляют метод NewReader для непосредственного создания соответствующей реализации Reader из переменной типа []byteили типа.string

r := strings.NewReader("abcde")
// 或者是 bytes.NewReader([]byte("abcde"))
buf := make([]byte4)
for {
 n, err := r.Read(buf)
 fmt.Println(n, err, buf[:n])
 if err == io.EOF {
  break
 }
}

Еще одно отличие состоит в том, что библиотека bytes имеет функциональность Buffer, а библиотека strings — нет.

var buf bytes.Buffer
fmt.Fprintf(&buf, "Size: %d MB."85)
s := buf.String()) // s == "Size: 85 MB."

Подвести итог

Что касается интерфейса io.Reader, io.Writerего можно просто понимать как источник чтения и источник записи. То есть, пока Readerметод Readреализован, эта штука может использоваться как источник чтения, который может содержать данные и быть прочитанным нами. Writerтоже так.

Выше приведено краткое изложение сценариев использования и проблем, которые необходимо решить каждой библиотеке для встроенных библиотек языка Go, которые я часто использую при выполнении I/Oопераций на языке Go.Правильно выбрать соответствующую библиотеку, когда это необходимо для завершения I/Oоперация. Если описание в статье неверное, пожалуйста, оставьте сообщение для его исправления, а также вы можете обсудить и внести предложения по содержанию статьи в сообщении.

Рекомендуемое чтение: