【发布时间】:2017-10-31 00:32:46
【问题描述】:
我已经尝试在一个 for 循环中重新声明/分配一个 base64 解码器并使用 os.Seek 函数在此之前的循环结束时返回到文件的开头,以便调用函数(在此测试用例中为 PrintBytes)能够在整个 for 循环中一次又一次地从头到尾处理文件。
这是我的(我确信非常不习惯)代码,在 main() 中的 main for 循环的第二次迭代期间,它无法将第二个字节读入长度为 2 和容量为 2 的 [] 字节:
package main
import (
"encoding/base64"
"io"
"log"
"net/http"
"os"
)
var (
remote_file string = "http://cryptopals.com/static/challenge-data/6.txt"
local_file string = "secrets_01_06.txt"
)
func main() {
f, err := os.Open(local_file)
if err != nil {
DownloadFile(local_file, remote_file)
f, err = os.Open(local_file)
if err != nil {
log.Fatal(err)
}
}
defer f.Close()
for blocksize := 1; blocksize <= 5; blocksize++ {
decoder := base64.NewDecoder(base64.StdEncoding, f)
PrintBytes(decoder, blocksize)
_, err := f.Seek(0, 0)
if err != nil {
log.Fatal(err)
}
}
}
func PrintBytes(reader io.Reader, blocksize int) {
block := make([]byte, blocksize)
for {
n, err := reader.Read(block)
if err != nil && err != io.EOF {
log.Fatal(err)
}
if n != blocksize {
log.Printf("n=%d\tblocksize=%d\tbreaking...", n, blocksize)
break
}
log.Printf("%x\tblocksize=%d", block, blocksize)
}
}
func DownloadFile(local string, url string) {
f, err := os.Create(local)
if err != nil {
log.Fatal(err)
}
defer f.Close()
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
_, err = io.Copy(f, resp.Body)
if err != nil {
log.Fatal(err)
}
}
这段代码的输出可以在这里查看https://gist.github.com/tomatopeel/b8e2f04179c7613e2a8c8973a72ec085
我不明白的是这种行为: https://gist.github.com/tomatopeel/b8e2f04179c7613e2a8c8973a72ec085#file-bad_reader_log-L5758
我希望它从头到尾一次简单地将文件读取 2 个字节到 2 字节片中。为什么这里只读取 1 个字节?
【问题讨论】:
-
我不认为 base64 解码器是无状态的,所以
Seeking 底层阅读器在从 base64 阅读器读取之间可能会产生不可预知的结果。 -
这段代码的意图非常不清楚。我不得不回到最初的挑战来了解迭代块大小的情况(这看起来很奇怪,因为它没有使用累积的 n 来确保它最终读取块大小的字节)。只需
asBytes, err := ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, f)),然后继续处理数据作为字节。 (即:块长度之间的距离计算等) -
@Rob 此处代码的唯一目的是作为问题的演示。这是针对给定挑战的一些明显有缺陷的代码的修改摘录。我只是继续使用挑战中的文件,我想是出于懒惰。不过,我会考虑使用累积的 n,谢谢,我是 golang 的新手。