Golang中os.OpenFile为何会在文件中添加乱码
Golang中os.OpenFile为何会在文件中添加乱码
每次我使用 os.Open 打开文件时,都会在文件中添加空格和换行符。这些垃圾内容原本并不存在于文件中。我该如何解决这个问题?
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err.Error())
}
file.WriteString("test")
timestamp, _ := ioutil.ReadFile("log.txt")
tpl.ExecuteTemplate(w, page, string(timestamp))
}
实际输出:

期望输出:

更多关于Golang中os.OpenFile为何会在文件中添加乱码的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你在写入后关闭,所以这应该没问题,并且是“同步”的。
更多关于Golang中os.OpenFile为何会在文件中添加乱码的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
是的,你说得对。你不需要关闭输出文件,但至少应该确保在从它(文件)读取数据之前,输出缓冲区已被刷新。
如果这是真的,那为什么操作系统会有一个同步函数呢?
Sync 将文件的当前内容提交到稳定存储。通常,这意味着将文件系统内存中最近写入的数据副本刷新到磁盘。
直接文件访问是一个■■■■■■■,在语言中实现为无缓冲流的内容,在内核或文件系统驱动层面可能被缓冲。
然而,语言本身对此无能为力,因为与内核的接口是无缓冲的。
在你的应用程序和实际的磁盘之间,存在着许多抽象层。
其中一些会延迟和缓冲读写操作,而另一些则不会。
你最好的选择是不要读取“脏”文件,这些文件已经为写入而打开。
通常,这意味着将文件系统中最近写入数据的内存副本刷新到磁盘。
我如何使用“os”来刷新文件?
直接文件访问是一个■■■■■■■,在语言中实现为无缓冲流的内容,可能在内核或文件系统驱动层被缓冲。
你能进一步详细说明这一点吗?
输出缓冲区已被刷新
如何刷新 os?我读到以下内容:
为什么 os.File 中没有 flush 函数?
你会注意到
os.File没有.Flush()方法,因为它不需要,它是无缓冲的。对它的写入是直接进行系统调用来写入文件的。
我以为我已经说得很清楚了。使用 Sync 方法来刷新输出缓冲区。
func (f *File) Sync() error
Sync 将文件的当前内容提交到稳定存储。通常,这意味着将文件系统内存中最近写入数据的副本刷新到磁盘。
你最好的选择是不要读取“脏”文件,即那些已为写入而打开的文件。
那我应该怎么做呢?
func crondoc(msg string) {
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err.Error())
}
file.WriteString(msg + "\n")
defer file.Close()
}
Sibert 说: 去掉这个
问题的原因仍然是个谜。我认为这是 Go 添加的,但我无法确认。但一个快速的解决方法是向 CSS 中添加一行代码来移除这些空格。
white-space: pre-line;
来源: cron.go4webdev.org 网站图标:
goCron
goCron 自动化任务
之前:

之后:

仅供参考
你打开文件进行写入,然后又“再次”打开该文件进行读取。
这样是否更好:
package main
import (
"fmt"
"github.com/robfig/cron"
"os"
"time"
)
func crontsk() {
c := cron.New()
c.AddFunc("@every 5s", addstamp)
c.AddFunc("@every 60s", cleardoc)
c.Start()
time.Sleep(time.Duration(1<<63 - 1)) // 运行超过260年
}
func addstamp() {
t := time.Now()
t.String()
crondoc(t.Format("2006-01-02T15-04-05.000Z"))
}
func crondoc(msg string) {
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err.Error())
}
file.WriteString(msg + "\n")
defer file.Close()
}
func cleardoc() {
if err := os.Truncate("log.txt", 0); err != nil {
fmt.Println("Failed to truncate: %v", err)
}
}
goCron
goCron 自动化任务
据我所知,在使用 ioutil 时不必关闭文件?
os.OpenFile 本身不会在文件中添加乱码。问题出现在你的代码逻辑中:文件没有正确关闭,导致缓冲区内容没有完全写入磁盘。当你立即读取文件时,可能读取到的是未刷新的缓冲区内容。
以下是修正后的代码:
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
// 1. 使用正确的标志位打开文件
file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Println(err.Error())
return
}
defer file.Close() // 3. 确保文件关闭
// 2. 写入数据
_, err = file.WriteString("test")
if err != nil {
fmt.Println(err.Error())
return
}
// 4. 强制刷新到磁盘(可选,Close()会自动执行)
file.Sync()
// 5. 重新打开文件读取,确保获取最新内容
timestamp, err := ioutil.ReadFile("log.txt")
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(string(timestamp))
}
关键修改点:
- 添加
os.O_CREATE标志:确保文件不存在时会被创建 - 添加错误处理:检查
WriteString的返回值 - 使用
defer file.Close():确保文件描述符被释放,缓冲区内容刷新到磁盘 - 调用
file.Sync():强制将内容同步到磁盘(在需要立即读取的场景下很有用) - 重新打开文件读取:避免读取未刷新的文件句柄
常见问题排查:
如果问题仍然存在,检查:
- 文件是否被其他进程占用
- 磁盘空间是否充足
- 文件权限是否正确
// 调试方法:检查文件大小
info, _ := file.Stat()
fmt.Printf("File size: %d bytes\n", info.Size())
注意:ioutil.ReadFile 会读取整个文件,包括可能存在的BOM头或其他不可见字符。使用 hex.Dump 可以查看原始字节:
import "encoding/hex"
fmt.Printf("%s", hex.Dump(timestamp))


