Golang read from pipe считывает тонны данных
Я пытаюсь прочитать архив, который просмолен, потоковый, в stdin, но я как-то читаю далеко больше данных в трубе, чем tar отправляет.
Я выполняю свою команду так:
tar -cf - somefolder | ./my-go-binary
исходный код выглядит следующим образом:
package main
import (
"bufio"
"io"
"log"
"os"
)
// Read from standard input
func main() {
reader := bufio.NewReader(os.Stdin)
// Read all data from stdin, processing subsequent reads as chunks.
parts := 0
for {
parts++
data := make([]byte, 4<<20) // Read 4MB at a time
_, err := reader.Read(data)
if err == io.EOF {
break
} else if err != nil {
log.Fatalf("Problems reading from input: %s", err)
}
}
log.Printf("Total parts processed: %dn", parts)
}
для папки 100Mb tarred я получаю 1468 кусков 4MB (это 6.15 GB)! Кроме того, кажется, не имеет значения, насколько велика data []byte
массив: если я установлю размер куска в 40 МБ, я все равно получу ~1400 куски данных 40MB, что не имеет никакого смысла вообще.
есть ли что-то, что мне нужно сделать, чтобы прочитать данные из os.Stdin
правильно с Go?
2 ответов
ваш код неэффективен. Это выделение и инициализация data
каждый раз через петлю.
for {
data := make([]byte, 4<<20) // Read 4MB at a time
}
код reader
как io.Reader
- это неправильно. Например, вы игнорируете количество байтов, прочитанных _, err := reader.Read(data)
и вы не справляетесь err
правильно ошибок.
import "io"
type Reader interface { Read(p []byte) (n int, err error) }
Reader-это интерфейс, который обертывает базовый Метод read.
Read считывает до LEN (p) байтов в p. Возвращает количество байтов прочитайте (0
когда чтение обнаруживает ошибку или условие конца файла после успешно читая n > 0 байт, он возвращает количество прочитанных байтов. Он может вернуть ошибку (не-nil) из того же вызова или вернуть ошибка (и n == 0) от последующего вызова. Пример этого генерала дело в том, что считыватель возвращает ненулевое количество байтов в конце из входного потока может возвращаться err == EOF или err == nil. Этот следующее чтение должно возвращать 0, EOF независимо.
вызывающие всегда должны обрабатывать n > 0 байт, возвращенных до учитывая ошибку err. Делать это правильно обрабатывает ошибки ввода-вывода, произойдет после чтения некоторых байтов, а также обоих разрешенных EOF поведения.
реализации Read не рекомендуется возвращать нулевой байт считайте с нулевой ошибкой, за исключением случаев, когда len(p) == 0. Нужно лечить возврат 0 и nil как указание на то, что ничего не произошло; в в частности, он не указывает EOF.
реализации не должны сохранять p.
вот программа чтения файла модели, которая соответствует io.Reader
интерфейс:
package main
import (
"bufio"
"io"
"log"
"os"
)
func main() {
nBytes, nChunks := int64(0), int64(0)
r := bufio.NewReader(os.Stdin)
buf := make([]byte, 0, 4*1024)
for {
n, err := r.Read(buf[:cap(buf)])
buf = buf[:n]
if n == 0 {
if err == nil {
continue
}
if err == io.EOF {
break
}
log.Fatal(err)
}
nChunks++
nBytes += int64(len(buf))
// process buf
if err != nil && err != io.EOF {
log.Fatal(err)
}
}
log.Println("Bytes:", nBytes, "Chunks:", nChunks)
}
выход:
2014/11/29 10:00:05 Bytes: 5589891 Chunks: 1365
читать документацию читать:
Read считывает данные в p. Он возвращает количество байтов, прочитанных в p. Это вызовы читаются не более одного раза на базовом читателе, поэтому n может быть меньше чем лен (п). В EOF количество будет равно нулю, а err будет io.ВФ.
вы не читаете 4 МБ одновременно. Вы предоставляете буферное пространство и отбрасываете целое число, которое сказало бы вам, сколько прочитано на самом деле. Буфера максимальное, но обычно 128k, похоже, читается за вызов, по крайней мере, в моей системе. Попробуйте сами:
// Read from standard input
func main() {
reader := bufio.NewReader(os.Stdin)
// Read all data from stdin, passing the data as parts into the channel
// for processing.
parts := 0
for {
parts++
data := make([]byte, 4<<20) // Read 4MB at a time
amount , err := reader.Read(data)
// WILL NOT BE 4MB!
log.Printf("Read: %v\n", amount)
if err == io.EOF {
break
} else if err != nil {
log.Fatalf("Problems reading from input: %s", err)
}
}
log.Printf("Total parts processed: %d\n", parts)
}
вы должны реализовать логику для обработки различных читать суммы.