0

练习 7.5:包中
LimitReader函数io接受一个io.Reader r和一个字节数n,并返回另一个从字节Reader读取r但在n字节后报告文件结束条件的函数。实施它。

func LimitReader(r io.Reader, n int64) io.Reader

如何实施?


下面是我的代码,我知道它不对。

type MyReader struct {
    bytes []byte
    length int
}

func (myReader *MyReader) Read (p []byte) (int, error) {
    fmt.Println("be invoked")
    myReader.bytes = p
    myReader.length = len(p)
    fmt.Printf("lenght: %d\n" , myReader.length)
    return len(p), nil
}
func LimitReader(r io.Reader, n int64) io.Reader {
    filecontent, _:= ioutil.ReadFile("./testfile.txt")
    r.Read(filecontent[:n])
    return r
}

func main() {
    myReader := &MyReader{}
    r := LimitReader(myReader, 100)
    filecontent, _:= ioutil.ReadFile("./testfile.txt")
    fmt.Println(r.Read(filecontent))
}
4

1 回答 1

4

您似乎不清楚您需要做什么的概念。

您需要创建一个具有以下签名的函数:

func LimitReader(r io.Reader, n int64) io.Reader

也就是说,一个r io.Reader和一个n数字被传递给它,你必须返回一个新的io.Reader。当有人从返回的阅读器中读取时,读取的数据必须来自传递的r阅读器,并且应该自动计算读取的字节数;如果读取的字节数超过了这个n数,它就不能再从中读取更多的字节,r而是返回io.EOF用于指示已到达流末尾的字节。可能是r阅读器有更多字节(意味着可以从中读取更多字节),但这不应该被读取和返回:这就是LimitedReader.

如果您认为您现在了解问题,请暂时停止阅读答案,并尝试自己实施。下面是一个示例解决方案。


这个确切的功能已经存在于io包中,并且具有相同的名称:io.LimitReader().

// LimitReader returns a Reader that reads from r
// but stops with EOF after n bytes.
// The underlying implementation is a *LimitedReader.
func LimitReader(r Reader, n int64) Reader { return &LimitedReader{r, n} }

它返回 的值*io.LimitedReader,其实现如下:

// A LimitedReader reads from R but limits the amount of
// data returned to just N bytes. Each call to Read
// updates N to reflect the new amount remaining.
type LimitedReader struct {
    R Reader // underlying reader
    N int64  // max bytes remaining
}

func (l *LimitedReader) Read(p []byte) (n int, err error) {
    if l.N <= 0 {
        return 0, EOF
    }
    if int64(len(p)) > l.N {
        p = p[0:l.N]
    }
    n, err = l.R.Read(p)
    l.N -= int64(n)
    return
}

花一两分钟尝试自己理解代码。如果您遇到困难或一切都不清楚,请继续阅读。

解释代码:

io.LimitedReader是一个结构体,其中包含它读取的读取器,以及无需报告仍可读取的字节数io.EOF。因此,LimitReader()只需返回此结构的值,其中参数rn分配给字段RN结构。更具体地说,返回这个结构的地址,因为LimitedReader.Read()有指针接收器,所以只有一个指向它的指针实现io.Reader。它有一个指针接收器,因为该Read()方法(可能)修改结构的字段,所以需要一个指针才能做到这一点(否则只会修改一个副本,该副本在Read()方法返回后被丢弃)。

LimitedReader.Read()首先检查N告诉我们可以返回多少字节的字段,如果没有更多的“允许”,作为一个行为良好的受限阅读器,它会立即返回io.EOF而不从源读取更多字节:

if l.N <= 0 {
    return 0, EOF
}

如果N是正数,则意味着可能会读取并返回一些字节,但不会超过N,因此如果p传递给的切片Read()具有更大的长度,我们会对其重新切片,这样对源读取器的调用就不会读取超过我们应该读取的内容允许:

if int64(len(p)) > l.N {
    p = p[0:l.N]
}

最后一部分只是从源读者那里实际阅读:

n, err = l.R.Read(p)

它返回实际读取的字节数,以及一个可选的错误(读取是否遇到错误)。由于我们即将返回这些,我们必须管理现在返回的字节数,我们必须从允许的剩余字节中减去它:

l.N -= int64(n)
return
于 2016-10-11T07:03:31.637 回答