Golang从二进制数据中读取字符串的方法

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

print

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

8 回复

这对你有效吗?还是你仍然需要帮助?

更多关于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)
}

根据你的代码,它看起来会读取文件的前8个字节并将其解释为float64。根据你的截图,你实际上需要偏移量14处的数据(如果我现在在手机屏幕上数点正确的话)。在调用binary.Read之前,你应该调用f.Seek来将文件位置设置到你要读取的数据起始偏移量,然后再调用binary.Read

对于你想要的字符串,你同样需要进行定位操作,但你不需要使用binary.Read,你可以直接切片读取的字节,然后转换为字符串。这些字符串的长度总是相同的吗?还是你需要检查文件的其他偏移量来确定字符串的长度?

func main() {
    fmt.Println("hello world")
}

它能够运行,但我的代码不够整洁 😟

    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
}

选择哪种方法取决于二进制文件中字符串的具体存储格式。需要先确定字符串是固定长度、空字符结尾还是带长度前缀,以及使用何种字符编码。

回到顶部