I've started studying Go recently as a side project and have been trying to get a better handle around the Reader interface. Specifically, I'm trying to get contents from a website, and then reading it to a bytes slice.
I am aware that the ioutils.ReadAll function is the canonical way to get the data, but I'm curious why the original function I wrote has repeated content at the end of the output.
Code: package main
import(
"net/http"
"fmt"
)
func main() {
// retrieve url from hacker news.
resp, err := http.Get("http://news.ycombinator.com/")
if err != nil {
// handle error
}
defer resp.Body.Close()
text := make([]byte, 500)
buf := make([]byte, 200)
i, _ := resp.Body.Read(buf)
for i != 0 {
text = append(text,buf...)
i, _ = resp.Body.Read(buf)
}
fmt.Println(resp.ContentLength)
fmt.Println(resp.Status)
fmt.Printf("%q
", text)
}
Content:
(...)Search:
<input type=\"text\" name=\"q\" value=\"\" size=\"17\" autocorrect=\"off\" spellcheck=\"false\" autocapitalize=\"off\" autocomplete=\"false\"></form>
</center></td></tr>
</table></center></body></html>
put type=\"text\" name=\"q\" value=\"\" "
As you can see, for a reason I don't quite understand, one part of the text is repeated at the end after the closed tags; 'nput type=\"text\" name=\"q\" value=\"\" "'.
Maybe this is something related to the buffer not being cleared maybe? Could anyone offer some insight as to what I am getting wrong?
The io.Reader
interface returns the number of bytes read and an error value. You need to make use of both values.
The int
return value shows tells you how many bytes have been read into your the buffer, and error informs you of error conditions as well as when you've reached EOF. A Reader may also return bytes read and an io.EOF
on the same call, so you should handle that as well.
Also note that you create a slice for text
of 500 bytes, but then you append to it, leaving 500 null characters at the beginning.
var text []byte
buf := make([]byte, 256)
var n int
var err error
for err == nil {
n, err = resp.Body.Read(buf)
text = append(text, buf[:n]...)
}
if err != io.EOF {
log.Fatal("error:", err)
}
(Unrelated to Go, blocks of memory tend to work most efficiently when they are aligned to powers of 2.)