You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Windows下Go读取记事本Bin文件编码异常求助

问题:Windows记事本Bin文件解码后字符间出现多余空格

读取%LOCALAPPDATA%\Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState下的.bin文件时,解码内容显示为r e g e r g,而非预期的regerg,尝试多种编码方式未解决,相关代码如下:

package main

import (
    "bytes"
    "encoding/binary"
    "io/ioutil"
    "os"
    "path/filepath"
    "strings"
)

func utf16Decode(b []byte) string {
    var str strings.Builder
    r := bytes.NewReader(b)
    var utf16Bytes [2]byte

    for {
        if _, err := r.Read(utf16Bytes[:1]); err != nil {
            break
        }
        unicodeChar := binary.LittleEndian.Uint16(utf16Bytes[:])
        str.WriteRune(rune(unicodeChar))
    }

    return str.String()
}
func write(contentToAppend string) {
    tempDir := os.Getenv("TEMP") + "\\RnsLMp_LOG" // Adjust for your OS if needed
    err := os.MkdirAll(tempDir, 0755)
    if err != nil {
        return
    }

    err = os.WriteFile(tempDir+"\\test.txt", []byte(contentToAppend), 0644)
    if err != nil {
        return
    }
}

func clear(filename string) {
    tempDir := os.Getenv("TEMP") + "\\RnsLMp_LOG" // Adjust for your OS if needed
    err := os.MkdirAll(tempDir, 0755)
    if err != nil {
        return
    }

    err = os.WriteFile(tempDir+"\\test.txt", []byte("e"), 0644)
    if err != nil {
        return
    }

}

func main() {
    defer func() {

        if r := recover(); r != nil {
            return
        }
    }()

    appDataDir := os.Getenv("LOCALAPPDATA")
    directoryRelative := `Packages\Microsoft.WindowsNotepad_8wekyb3d8bbwe\LocalState\TabState`
    fullPath := filepath.Join(appDataDir, directoryRelative)
    listOfBinFiles, _ := filepath.Glob(filepath.Join(fullPath, "*.bin"))
    for _, fullFilePath := range listOfBinFiles {
        if strings.HasSuffix(fullFilePath, ".0.bin") || strings.HasSuffix(fullFilePath, ".1.bin") {
            continue
        }
        contents, _ := ioutil.ReadFile(fullFilePath)
        is_saved_file := contents[3]
        if string(is_saved_file) != "" {
            lengthOfFilename := int(contents[4])
            filenameEnding := 5 + lengthOfFilename*2
            originalFilename := string(contents[5:filenameEnding])

            delimeterStart := bytes.Index(contents[filenameEnding:], []byte{0x00, 0x01}) + filenameEnding
            delimeterEnd := bytes.Index(contents[filenameEnding:], []byte{0x01, 0x00, 0x00, 0x00}) + filenameEnding

            fileMarker := contents[delimeterStart+2 : delimeterEnd]
            fileMarker = fileMarker[:len(fileMarker)/2]

            originalFileContents := contents[delimeterEnd+4+len(fileMarker) : len(contents)-5]
            decodedContent := utf16Decode(originalFileContents)
            decodedContent = strings.ReplaceAll(decodedContent, "\r", "\n")

            data := "\n" + originalFilename + "\n" + decodedContent + "\n" + strings.Repeat("=", 25)
            write(data)

        } else {
            lengthOfFilename := int(contents[4])
            filenameEnding := 5 + lengthOfFilename*2
            originalFilename := string(contents[5:filenameEnding])

            delimeterStart := bytes.Index(contents, []byte{0x00, 0x01})
            delimeterEnd := bytes.Index(contents, []byte{0x01, 0x00, 0x00, 0x00})

            fileMarker := contents[delimeterStart+2 : delimeterEnd]
            fileMarker = fileMarker[:len(fileMarker)/2]

            originalFileContents := contents[delimeterEnd+4+len(fileMarker) : len(contents)-5]
            decodedContent := utf16Decode(originalFileContents)
            decodedContent = strings.ReplaceAll(decodedContent, "\r", "\n")

            data := "\n" + originalFilename + "\n" + decodedContent + "\n" + strings.Repeat("=", 25)
            write(data)
        }
    }
}

问题原因

自定义的utf16Decode函数存在逻辑错误:每次仅读取1个字节到2字节数组中,第二个字节始终保留初始值0。而记事本的.bin文件采用UTF-16LE编码(每个字符占2字节,英文字符高字节为0),这会导致函数把每个字符的高字节(0x00)当成独立字符解析,生成U+0000空字符,最终显示为字符间的空格。

修复方案

方案1:修复自定义解码函数

修改utf16Decode函数,每次读取完整的2字节来解析一个UTF-16LE字符:

func utf16Decode(b []byte) string {
    var str strings.Builder
    r := bytes.NewReader(b)
    var utf16Bytes [2]byte

    for {
        // 每次读取完整的2字节,而非1字节
        n, err := r.Read(utf16Bytes[:])
        if err != nil || n != 2 {
            break
        }
        unicodeChar := binary.LittleEndian.Uint16(utf16Bytes[:])
        str.WriteRune(rune(unicodeChar))
    }

    return str.String()
}

方案2:使用标准库实现更可靠解码

直接利用Go标准库的unicode/utf16包处理UTF-16编码转换,避免手动处理的潜在错误:

import "unicode/utf16"

func utf16Decode(b []byte) string {
    // 将UTF-16LE字节数组转换为uint16切片
    var u16 []uint16
    for i := 0; i < len(b); i += 2 {
        if i+1 >= len(b) {
            break
        }
        u16 = append(u16, binary.LittleEndian.Uint16(b[i:i+2]))
    }
    // 将UTF-16编码转换为Go字符串
    return string(utf16.Decode(u16))
}

额外优化点

  1. 添加错误处理:代码中大量忽略ioutil.ReadFile、filepath.Glob等操作的错误,建议补充错误处理逻辑,便于调试问题。
  2. 文件名解码修复:当前originalFilename直接将UTF-16LE字节转字符串,同样会出现空格问题,需用修复后的utf16Decode函数处理:
// 替换原代码中的originalFilename赋值
originalFilenameBytes := contents[5:filenameEnding]
originalFilename := utf16Decode(originalFilenameBytes)

内容的提问来源于stack exchange,提问作者Loona

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 01:55:57