go - Go中的问题是附加到[]字节,写入文件并读取它
问题描述
我正在尝试解析大量 IP(~20mb 或 400 万个 IP),将它们作为字节存储在文件中,然后再读取它们。
我遇到的问题是我希望它们按排序顺序存储,但我看到随机字节片在读回它们时看起来像损坏的 IP。
// 让它被称为 generator.go
var buf []byte
// So this is where we build up `buf`, which we later write to a file.
func writeOut(record RecordStruct) {
// This line is never hit. All slices have a length of 4, as expected
if len(record.IPEnd.Bytes()) != 4 {
fmt.Println(len(record.IPEnd.Bytes()), record.IPEnd.Bytes())
}
// Let's append the IP to the byte slice with a seperater of 10 null bytes which we will later call bytes.Split on.
buf = append(buf, append(record.IPEnd.Bytes(), bytes.Repeat([]byte{0}, 10)...)...)
}
func main () {
// Called many times. For brevity I won't include all of that logic.
// There are no Goroutines in the code and running with -race says all is fine.
writeOut(...)
err := ioutil.WriteFile("bin/test", buf, 0644)
}
阅读器.go
func main() {
bytez, err := ioutil.ReadFile("bin/test")
if err != nil {
fmt.Println("Asset was not found.")
}
haystack := bytes.Split(bytez, bytes.Repeat([]byte{0}, 10))
for _, needle := range haystack {
// Get's hit maybe 10% of the time. The logs are below.
if len(needle) != 4 {
fmt.Println(fmt.Println(needle))
}
}
}
[188 114 235]
14 <nil>
[120 188 114 235 121]
22 <nil>
[188 148 98]
13 <nil>
[120 188 148 98 121]
21 <nil>
正如您所看到的,IP 位太少或太多。
如果我更改日志以更好地说明问题,看起来最后一个八位字节溢出了?
Fine: [46 36 202 235]
Fine: [46 36 202 239]
Fine: [46 36 202 255]
Weird: [46 36 203]
Weird: [0 46 36 203 1]
Fine: [46 36 203 3]
Fine: [46 36 203 5]
Fine: [46 36 203 7]
Fine: [46 36 203 9]
解决方案
当 IP 地址以零字节结尾时,代码不会正确拆分字节。通过将地址转换为 16 字节表示并存储不带分隔符的 16 字节记录来修复。
您可以使用以下命令有效地将 v4 和 v6 地址的混合附加到缓冲区:
switch len(p) {
case net.IPv6len:
buf = append(buf, p...)
case net.IPv4len:
buf = append(buf, v4InV6Prefix...)
buf = append(buf, p...)
default:
// handle error
}
其中v4InV6Prefix
是值为 的包级变量 []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
。
将文件读取为 v6 地址:
buf, err := ioutil.ReadFile(xxx)
if err != nil {
// handle error
}
for i := 0; i < len(buf); i += 16 {
addr := net.IP(buf[i:i+16])
// do something with addr
}
请注意,也可以使用 io.Reader 和 io.Writer 以增量方式读取和写入文件。此答案中的代码与应用程序一次性读取和写入文件的问题中的代码相匹配。
推荐阅读
- node.js - 无法在 Lambda 中创建带有除 UTC 之外的时区的日期对象
- bash - 用于检查和处理文件的无限循环 bash 脚本
- python - Pyomo中的嵌套总和
- java - 无法从 Swing 客户端创建初始上下文
- django - Django rest-auth:从其他视图集调用 RegisterView;sensitive_post_parameters 没有收到 HttpRequest
- powershell - PowerShell中的“$($var)”和(“$var”)有什么区别
- javascript - Angular:刷新浏览器页面后无法重新加载数据
- angular - 将文件从浏览器表单存储到 MinIO (Angular2)
- python - 您将如何从文本数据中识别身体部位和受伤类型?
- git - 如何检查分支是否已合并到其他分支?