Golang服务端应用无法写入文件的问题如何解决
Golang服务端应用无法写入文件的问题如何解决 我正在开发一个简单的Web服务器,将所有接收到的TCP数据包写入output.txt文件,因此编写了以下代码:
func handleRequest(conn net.Conn) {
// 创建缓冲区来保存传入数据
buf := make([]byte, 1024)
// 将传入连接读取到缓冲区
size, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading:", err.Error())
}
s := string(buf[:size])
fmt.Println(s)
perm := os.FileMode(0644)
err = ioutil.WriteFile("output.txt", buf[:size], perm)
check(err)
// 处理完成后关闭连接
conn.Close()
}
程序能够创建output.txt文件,但不会向其中写入任何内容。所有"服务器部分"都运行正常(能够正确输出变量s)。
更多关于Golang服务端应用无法写入文件的问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
这些限制是故意设置的,因为发送TCP连接的设备存在特定要求
这是什么字符串?如果它不以换行符结尾,可能会被你的提示符覆盖,例如。
你能在不涉及网络相关功能的情况下重现文件写入的错误行为吗?如果可以,请分享简化后的代码。
xxd版本输出了什么?告诉我们最后一行就足够了。甚至最后两个字节可能就足以说明问题。
有一个 check() 函数:
func check(e error){
if e != nil {
panic(e)
}
}
它确实包含该字符串,但为什么cat命令不显示这个字符串,而xxd命令却可以?
00000000: 6865 6c6c 6f0d hello.
"hello"是我用来测试的字符串
我指的是buf[:size]中的内容,问题是:为什么我用"cat output.txt"看不到它,但用"cat output.txt | xdd"就能看到? 我可以用另一个程序(比如用C语言写的)打开它吗?
在写入和错误检查后进行日志记录,不是关于它是否工作的问题,而是关于代码是否被执行到的问题。
请尝试创建一个包含主包的单一Go文件,以复现您的问题。当然,最好是不涉及网络连接的复现方式。
func main() {
fmt.Println("hello world")
}
它会引发恐慌还是继续运行?(请记住,恐慌信息会输出到 stderr,根据程序运行方式的不同,可能会被记录到不同的文件中或完全不显示!)
你是否尝试过在关闭连接前后添加日志记录?
如果直接将 ioutil.WriteFile 替换为直接调用 os.Open、io.Write 等方法,是否能正常工作?
但是你的检查函数呢?从你的代码来看,似乎即使在写入过程中出现错误,你仍会继续报告成功,这就是我想查看你检查函数的原因。
编辑
即使你说数据不会超过1千字节,数据仍可能以分块方式传递给你。因此你应该定义一个能适应这种情况的明确协议。
另外我仍然认为关闭连接存在风险。调用方可能会在你关闭连接后继续使用它,或者被重复关闭。
绝不要释放不属于你的资源!
0x0d 是十进制 13,十进制 13 在 ASCII 中对应 \r,\r 表示将光标移动到同一行的开头。
因此 cat output.txt 会先打印 hello,然后将光标移回到 hello 中 h 的打印位置,接着用你的 shell 提示符覆盖它。
所以要检查文件是否为空,请始终检查其确切的字节大小:ls -l output.txt
func main() {
fmt.Println("hello world")
}
check 会产生任何输出吗?我在你的代码中找不到它的定义……
另外这个论坛使用 Markdown 风格的代码格式化,所以你必须将代码缩进 4 个空格,或者用三个反引号包裹并可选添加语言标注:
// your code goes here
BBcode 在这里不起作用。
除了错误检查和 Markdown 的问题之外,我发现了你代码中的一些问题:
- 当你一次性接收到超过 1024 字节时,它可能会失败,或者至少可能无法正确处理这些数据。
- 你正在关闭一个在调用端可能仍在使用的连接。
抱歉,但我无法在本地使用您的代码片段复现此问题。
在我补充了缺失的部分(package、import (…) 和 const (…))后,我成功编译并运行了程序。
执行 echo "test" | nc localhost 3333 既产生了预期输出,也创建了文件,其内容如下:
$ cat output.txt | xxd
00000000: 7465 7374 0a test.
也许您查看文件的位置不正确,而您正在查看的是残留文件?
请检查 Linux 系统中文件的各种日期属性,特别是修改日期(mdate)。
问题出现在文件写入操作上。当使用ioutil.WriteFile时,它会截断现有文件然后写入新内容。如果多个连接同时调用这个函数,可能会导致写入冲突或数据被覆盖。
以下是修复后的代码:
func handleRequest(conn net.Conn) {
buf := make([]byte, 1024)
size, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading:", err.Error())
conn.Close()
return
}
s := string(buf[:size])
fmt.Println(s)
// 使用追加模式打开文件
file, err := os.OpenFile("output.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Error opening file:", err.Error())
conn.Close()
return
}
defer file.Close()
// 写入数据并添加换行符
_, err = file.Write(buf[:size])
if err != nil {
fmt.Println("Error writing to file:", err.Error())
}
conn.Close()
}
或者使用带锁的版本确保线程安全:
import "sync"
var fileMutex sync.Mutex
func handleRequest(conn net.Conn) {
buf := make([]byte, 1024)
size, err := conn.Read(buf)
if err != nil {
fmt.Println("Error reading:", err.Error())
conn.Close()
return
}
s := string(buf[:size])
fmt.Println(s)
fileMutex.Lock()
defer fileMutex.Unlock()
file, err := os.OpenFile("output.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("Error opening file:", err.Error())
conn.Close()
return
}
defer file.Close()
_, err = file.Write(buf[:size])
if err != nil {
fmt.Println("Error writing to file:", err.Error())
}
conn.Close()
}
主要修改:
- 使用
os.OpenFile以追加模式打开文件 - 添加了错误处理和适当的连接关闭
- 第二个版本添加了互斥锁来防止并发写入冲突
如果仍然无法写入,检查文件权限和磁盘空间,并确保程序对当前目录有写权限。


