Другой результат при последовательном запуске io.Copy (os.Stdout, & r) на Голанге - PullRequest
0 голосов
/ 19 ноября 2018

Я играю вокруг Голанга. О io.Copy Я поместил 2 последовательных кода io.Copy в код, но я ожидаю, что он выведет результат дважды (testtesttest). Но второй ноль. Может кто-нибудь помочь объяснить, почему? ТКС

package main

import (
    "io"
    "os"
    "strings"
    "fmt"

)

type testReader struct {
    w io.Reader
    str string

}


func (tt *testReader) Read (b []byte) (n int, err error) {


    io.Copy(os.Stdout, tt.w)
     n, err = tt.w.Read(b)
     if tt.w !=nil {
        return 0,io.EOF
      }
    return
}

func main() {
    s := strings.NewReader("testtesttest!!!")
    r := testReader{s,"ttthhh"}
    fmt.Println(&r)
    io.Copy(os.Stdout, &r)
//  s.Seek(0,0)   // solution from Poy's answer
    io.Copy(os.Stdout, &r)

}

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Быстрое добавление ко всем правильным ответам (@poy и @JRLambert), предоставленным до сих пор ... Используйте io.TeeReader или io.MultiWriter для случаев, когда вы хотите использовать io.Copy более одного раза.Ниже приведены некоторые примеры использования каждого .


Использование io.TeeReader

package main

import (
    "bytes"
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "io"
    "io/ioutil"
    "os"
)

func main() {
    sourceFile, _ := os.Open("source/ebook.pdf")

    var buf bytes.Buffer
    tee := io.TeeReader(sourceFile, &buf)

    process := func(sourceReader io.Reader) {
        targetFile, _ := os.Create("target/ebook.pdf")
        defer targetFile.Close()
        if _, err := io.Copy(targetFile, sourceReader); err != nil {
            fmt.Println(err)
        }
    }

    process(tee)
    fmt.Println(checksum(&buf))
}

func checksum(buf *bytes.Buffer) string {
    h := md5.New()
    b, _ := ioutil.ReadAll(buf)
    if _, err := h.Write(b); err != nil {
        fmt.Println(err)
    }
    return hex.EncodeToString(h.Sum(nil)[:16])
}


Использование io.MultiWriter

package main

import (
    "bytes"
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "io"
    "io/ioutil"
    "os"
)

func main() {
    sourceFile, _ := os.Open("source/ebook.pdf")

    process := func(sourceReader io.Reader) {
        targetFile, _ := os.Create("target/ebook.pdf")
        defer targetFile.Close()

        var buf1, buf2 bytes.Buffer
        w := io.MultiWriter(targetFile, &buf1, &buf2)

        if _, err := io.Copy(w, sourceReader); err != nil {
            fmt.Println(err)
        }

        fmt.Println(checksum(&buf1))
        fmt.Println(checksum(&buf2))
    }

    process(sourceFile)

}

func checksum(buf *bytes.Buffer) string {
    h := md5.New()
    b, _ := ioutil.ReadAll(buf)
    if _, err := h.Write(b); err != nil {
        fmt.Println(err)
    }
    return hex.EncodeToString(h.Sum(nil)[:16])
}
0 голосов
/ 19 ноября 2018

Я собираюсь сократить приведенный пример до (поскольку есть немного шума):

package main

import (
    "io"
    "os"
    "strings"
)

func main() {
    s := strings.NewReader("testtesttest")
    io.Copy(os.Stdout, s) // Will print "testtesttest"
    io.Copy(os.Stdout, s) // Won't print anything
}

Причина, по которой вторая копия ничего не выдаст, - io.Reader (s) уже прочитано.Чтение с io.Reader не идемпотентно (вы не можете вызвать его дважды, чтобы получить одинаковые результаты). У него также нет способа «сбросить» его или что-либо еще.

Как указывал @JRLambert, у вас есть s.Seek () и s.Reset () , чтобы вы могли начать чтение снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...