Golang从二进制数据中读取字符串的方法
Golang从二进制数据中读取字符串的方法 大家好! 我正在尝试读取我的二进制文件,以便从不同位置获取字符串: 就像这样

func main() {
f, err := os.Open("binaryfile.bin")
if err != nil {
log.Fatalln(err)
}
defer f.Close()
var val float64
err = binary.Read(f, binary.LittleEndian, &val)
if err != nil {
log.Fatalln(err)
}
fmt.Println(pi)}
我完全搞不懂了。
更多关于Golang从二进制数据中读取字符串的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
感谢您的回答。 我的想法是找到第一个IP地址,然后读取其后的数据,因为中间的长度是固定的,就像这个粘贴板十六进制一样。
我是Golang的初学者和新手。
您可以将重复的部分放入一个函数中:https://play.golang.org/p/iflkAKaXbuh
我不太确定您使用 strings.ReplaceAll(string(_ip[:]), " ", " ") 想要实现什么效果:这会将所有空格替换为空格,所以本质上是一个无操作。
func main() {
fmt.Println("hello world")
}
我的新代码
func main() {
file, err := os.Open("data.bin")
if err != nil {
log.Fatal(err)
}
defer file.Close()
o2, err := file.Seek(110, io.SeekCurrent) <---- First occurrence
byteSlice := make([]byte, 32)
bytesRead, err := file.Read(byteSlice)
if err != nil {
log.Fatal(err)
}
log.Printf("IP: %s\n", byteSlice)
}
它能够运行,但我的代码不够整洁 😟
file, err := os.Open("data.bin")
check(err)
defer file.Close()
o1, err := file.Seek(110, 0) <--- 第一个位置
check(err)
_ip := make([]byte, 15)
ipRead, err := file.Read(_ip)
clean_ip := strings.ReplaceAll(string(_ip[:]), " ", " ")
o2, err := file.Seek(21, io.SeekCurrent)
check(err)
_user := make([]byte, 15)
userRead, err := file.Read(_user)
clean_user := strings.ReplaceAll(string(_user[:]), " ", " ")
o3, err := file.Seek(532, 0) <---- 第二个位置
check(err)
_pwd := make([]byte, 20)
pwdRead, err := file.Read(_pwd)
clean_pwd := strings.ReplaceAll(string(_pwd[:]), " ", " ")
skillian:
我不确定你(devdavid)使用
strings.ReplaceAll(string(_ip[:]), " ", " ")是想达到什么目的:这会把所有空格替换成空格,所以本质上是一个空操作。
通过查看文件转储内容,我猜测它们是 C 字符串。因此,这是试图用空格替换 NUL 字符。
一个更好的解决方案是使用 CToGoString 函数:
package main
import "fmt"
func CToGoString(c []byte) string {
n := -1
for i, b := range c {
if b == 0 {
break
}
n = i
}
return string(c[:n+1])
}
func main() {
// IPV4
c := []byte("\x34\x31\x2E\x31\x39\x31\x2E\x39\x37\x2E\x36\x32\x00\x00\x00")
fmt.Printf("%d %q\n", len(c), c)
g := CToGoString(c)
fmt.Printf("%d %q\n", len(g), g)
c = []byte("1.1.1.1\x00\x00\x00\x00\x00\x00\x00\x00")
fmt.Printf("%d %q\n", len(c), c)
g = CToGoString(c)
fmt.Printf("%d %q\n", len(g), g)
c = []byte("111.111.111.111")
fmt.Printf("%d %q\n", len(c), c)
g = CToGoString(c)
fmt.Printf("%d %q\n", len(g), g)
c = make([]byte, 15)
fmt.Printf("%d %q\n", len(c), c)
g = CToGoString(c)
fmt.Printf("%d %q\n", len(g), g)
}
Go Playground - The Go Programming Language
15 "41.191.97.62\x00\x00\x00"
12 "41.191.97.62"
15 "1.1.1.1\x00\x00\x00\x00\x00\x00\x00\x00"
7 "1.1.1.1"
15 "111.111.111.111"
15 "111.111.111.111"
15 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
0 ""
在Golang中从二进制数据读取字符串,需要根据字符串的编码和存储方式来处理。以下是几种常见情况的示例:
1. 读取固定长度的字符串(已知长度)
func readFixedString(f *os.File, length int) (string, error) {
buffer := make([]byte, length)
_, err := io.ReadFull(f, buffer)
if err != nil {
return "", err
}
// 去除可能的空字符
str := string(buffer)
if idx := strings.IndexByte(str, 0); idx != -1 {
str = str[:idx]
}
return str, nil
}
2. 读取以空字符结尾的C风格字符串
func readCString(f *os.File) (string, error) {
var bytes []byte
buf := make([]byte, 1)
for {
_, err := f.Read(buf)
if err != nil {
return "", err
}
if buf[0] == 0 {
break
}
bytes = append(bytes, buf[0])
}
return string(bytes), nil
}
3. 读取带长度前缀的字符串
func readPrefixedString(f *os.File) (string, error) {
var length uint32
err := binary.Read(f, binary.LittleEndian, &length)
if err != nil {
return "", err
}
buffer := make([]byte, length)
_, err = io.ReadFull(f, buffer)
if err != nil {
return "", err
}
return string(buffer), nil
}
4. 从特定位置读取字符串
func main() {
f, err := os.Open("binaryfile.bin")
if err != nil {
log.Fatalln(err)
}
defer f.Close()
// 先读取浮点数
var val float64
err = binary.Read(f, binary.LittleEndian, &val)
if err != nil {
log.Fatalln(err)
}
fmt.Println("Float value:", val)
// 从当前位置读取20字节的字符串
str, err := readFixedString(f, 20)
if err != nil {
log.Fatalln(err)
}
fmt.Println("String:", str)
// 跳转到特定偏移量读取
offset := int64(100) // 从文件开头偏移100字节
_, err = f.Seek(offset, io.SeekStart)
if err != nil {
log.Fatalln(err)
}
// 读取C风格字符串
cstr, err := readCString(f)
if err != nil {
log.Fatalln(err)
}
fmt.Println("C string:", cstr)
}
5. 使用bufio提高读取效率
func readStringsEfficiently(filename string) error {
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
reader := bufio.NewReader(f)
// 读取固定长度字符串
fixedStr := make([]byte, 50)
_, err = io.ReadFull(reader, fixedStr)
if err != nil {
return err
}
fmt.Println("Fixed string:", string(bytes.TrimRight(fixedStr, "\x00")))
// 读取一行(直到换行符)
line, err := reader.ReadString('\n')
if err != nil && err != io.EOF {
return err
}
fmt.Println("Line:", strings.TrimRight(line, "\n"))
return nil
}
6. 处理UTF-16编码的字符串
func readUTF16String(f *os.File, length int) (string, error) {
buffer := make([]byte, length*2) // UTF-16每个字符2字节
_, err := io.ReadFull(f, buffer)
if err != nil {
return "", err
}
// 转换为UTF-8
utf16 := make([]uint16, length)
for i := 0; i < length; i++ {
utf16[i] = binary.LittleEndian.Uint16(buffer[i*2:])
}
return string(utf16.Decode(utf16)), nil
}
选择哪种方法取决于二进制文件中字符串的具体存储格式。需要先确定字符串是固定长度、空字符结尾还是带长度前缀,以及使用何种字符编码。


