package main
import (
"bufio"
"bytes"
"encoding/unicode"
"fmt"
"io"
"os"
)
func main() {
inputFile, err := os.Open("input.txt")
if err != nil {
fmt.Println("Failed to open input file:", err)
return
}
defer inputFile.Close()
outputFile, err := os.Create("output.txt")
if err != nil {
fmt.Println("Failed to create output file:", err)
return
}
defer outputFile.Close()
reader := bufio.NewReader(inputFile)
writer := bufio.NewWriter(outputFile)
for {
data, err := reader.Peek(2)
if err != nil && err != io.EOF {
fmt.Println("Error peeking data:", err)
return
}
if len(data) < 2 {
break
}
// 读取UTF - 16编码的一个代码单元
r := unicode.ReplacementChar
if data[0]&0xfc == 0xd8 && len(data) >= 4 {
// 处理代理对
lead := uint16(data[0])<<8 | uint16(data[1])
trail := uint16(data[2])<<8 | uint16(data[3])
if unicode.IsSurrogate(lead) && unicode.IsSurrogate(trail) {
r = unicode.DecodeRune(lead, trail)
_, err = reader.Discard(4)
} else {
r = unicode.ReplacementChar
_, err = reader.Discard(2)
}
} else {
r = rune(uint16(data[0])<<8 | uint16(data[1]))
_, err = reader.Discard(2)
}
if err != nil && err != io.EOF {
fmt.Println("Error discarding data:", err)
return
}
var buf bytes.Buffer
n, err := buf.WriteRune(r)
if err != nil {
fmt.Println("Error writing rune to buffer:", err)
return
}
utf8Data := buf.Bytes()
_, err = writer.Write(utf8Data[:n])
if err != nil {
fmt.Println("Error writing data to output file:", err)
return
}
}
err = writer.Flush()
if err != nil {
fmt.Println("Error flushing writer:", err)
return
}
}
- 文件打开与关闭:
- 使用
os.Open
打开输入文件,使用os.Create
创建输出文件,并通过defer
语句确保文件在函数结束时正确关闭,避免资源泄漏。
- 读写器选择:
- 使用
bufio.NewReader
和bufio.NewWriter
分别创建带缓冲区的读取器和写入器,以减少I/O操作次数,提高效率。
- UTF - 16解码:
- 每次从输入文件中窥视(
Peek
)2个字节,因为UTF - 16编码每个代码单元是2个字节。
- 检查是否为代理对,如果是则读取接下来2个字节并使用
unicode.DecodeRune
解码。如果不是代理对,直接将2个字节转换为rune
。
- 使用
reader.Discard
丢弃已读取的数据。
- UTF - 8编码:
- 使用
buf.WriteRune
将解码后的rune
写入bytes.Buffer
,WriteRune
会将rune
编码为UTF - 8格式。
- 从
bytes.Buffer
获取UTF - 8编码的数据并写入输出文件。
- 错误处理:
- 对文件打开、窥视数据、丢弃数据、写入数据和刷新写入器等操作都进行了错误处理,确保程序在遇到错误时能给出相应提示并安全退出。