我写了一个小服务器,它以io.Reader
的形式接收一个数据块,添加一个标头并将结果传回给调用者。
我的实现并不是特别有效,因为我在内存中缓冲blob的数据,这样我就可以计算blob的长度,这需要构成标题的一部分。
我已经看到io.Pipe()
与io.TeeReader
的一些示例,但它们更多的是将io.Reader
拆分为两个,并将它们并行写出来。
我正在处理的blob大约是100KB,所以不是很大但是如果我的服务器忙碌,内存很快就会成为一个问题......
有什么想法吗?
func addHeader(in io.Reader) (out io.Reader, err error) {
buf := new(bytes.Buffer)
if _, err = io.Copy(buf, in); err != nil {
return
}
header := bytes.NewReader([]byte(fmt.Sprintf("header:%d", buf.Len())))
return io.MultiReader(header, buf), nil
}
我很欣赏从函数返回接口不是一个好主意,但是这段代码注定不会成为API,所以我不太关心这一点。
答案 0 :(得分:0)
通常,确定io.Reader中数据长度的唯一方法是读取直到EOF。有多种方法可以确定特定类型的数据长度。
func addHeader(in io.Reader) (out io.Reader, err error) {
n := 0
switch v := in.(type) {
case *bytes.Buffer:
n = v.Len()
case *bytes.Reader:
n = v.Len()
case *strings.Reader:
n = v.Len()
case io.Seeker:
cur, err := v.Seek(0, 1)
if err != nil {
return nil, err
}
end, err := v.Seek(0, 2)
if err != nil {
return nil, err
}
_, err = v.Seek(cur, 0)
if err != nil {
return nil, err
}
n = int(end - cur)
default:
var buf bytes.Buffer
if _, err := buf.ReadFrom(in); err != nil {
return nil, err
}
n = buf.Len()
in = &buf
}
header := strings.NewReader(fmt.Sprintf("header:%d", n))
return io.MultiReader(header, in), nil
}
这类似于net / http包determines the content length of the request body。