我试图读取一个归档文件,该归档文件正在被压缩、流式传输到stdin,但不知何故,我在管道中读取的数据比tar发送的数据多far个.

我像这样运行命令:

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: %d\n", parts)
}

对于一个data []byteMB的柏油文件夹,我将得到1468个4MB的块(6.15 GB)!此外,data []byte个数组的大小似乎并不重要:如果我将块大小设置为40MB,我仍然可以获得大约1400个40MB的数据块,这完全没有意义.

我需要做些什么才能用Go正确读取os.Stdin的数据吗?

推荐答案

你的代码效率很低.它在循环中每次分配和初始化data.

for {
    data := make([]byte, 4<<20) // Read 4MB at a time
}

reader作为io.Reader的代码是错误的.例如,您忽略了_, err := reader.Read(data)读取的字节数,并且没有正确处理err个错误.

Package io

import "io" 

type Reader

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

Reader是包装基本读取方法的接口.

READ最多将len(P)字节读入p.它返回字节数 读取(0<;=n<;=len(P))和遇到的任何错误.即使读了也行 返回n<;len(P),则在执行 打电话.如果某些数据可用,但不是len(P)字节,请读取 通常返回可用的内容,而不是等待更多.

When Read encounters an error or end-of-file condition after successfully reading n > 0 bytes, it returns the number of bytes read. It may return the (non-nil) error from the same call or return the error (and n == 0) from a subsequent call. An instance of this general case is that a Reader returning a non-zero number of bytes at the end of the input stream may return either err == EOF or err == nil. The next Read should return 0, EOF regardless.

Callers should always process the n > 0 bytes returned before considering the error err. Doing so correctly handles I/O errors that happen after reading some bytes and also both of the allowed EOF behaviors.

不鼓励Read的实现返回零字节 计数无错误,除非len(P)==0.来电者应该请客 返回0和零,表示什么都没有发生; 具体地说,它并不表示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

Go相关问答推荐

带有Go map[字符串]字符串的持久磁盘

Go-Colly:将数据切片为POST请求

禁用Golang中的终端

Wamtime Memory中的‘Offset’是什么?Read?

如何使用 go 读取 RDF xml 文件中的 XML 命名空间属性

Kusto Go API 从多个表查询

io.Reader 无限循环与 fmt.Fscan

判断一个区域内的纬度/经度点

动态 SQL 集 Golang

如何在自定义验证函数中获取 struct 名称

如何将具有嵌入式 struct 的 struct 展平为 json

如何使用 Status 字段创建 Kubernetes 对象?

panic :拨号 tcp:在 172.22.64.1:53 上查找 bookstoreDB:没有这样的主机

为什么我不能使用来自 gocloak 中 Login() 的访问令牌在 KeyCloak 中创建新客户端?

Unescape 在 rss 中两次逃脱了标题

在 Golang 中使用 OR 条件验证 struct 的两个字段

从 Go struct 中提取标签作为 reflect.Value

Go Flag 用法 描述 包含 Word 值

如何断言类型是指向golang中接口的指针

Gin中测试模式有什么用