Golang中如何简单地将字符串和变量写入文件

Golang中如何简单地将字符串和变量写入文件 我一直在学习Go by Example网站上的教程,但感觉有些吃力。

在写入文件之前,我是否需要为要写入的内容创建缓冲区?我发现了太多创建文件和写入文件的方法,以至于不太确定实际发生了什么过程。

如果有人能提供一些简单的Python到Golang的对比示例供我学习和讨论,我将不胜感激。

谢谢

18 回复

如何写入一个没有内容的文件(缓冲区)?

更多关于Golang中如何简单地将字符串和变量写入文件的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


缓冲仅在需要写入大量数据时才需要使用。你说的缓冲概念具体指什么?我可以帮你解答。

老实说我不太确定该从哪里开始。您是否有关于使用缓冲区的相关资料或链接?另外,什么时候应该使用缓冲区呢?

谢谢

感谢两位的代码审查。另外,@inancgumus 感谢您展示的“缓冲区”示例,这不仅让我持续思考缓冲区的概念,而且获得两个不同版本对我非常有帮助。

RR

我有点困惑——我以为我通过以下代码行将’c’的输出转换为字符串并将新类型保存到’g’:

g := string([]byte(c[:]))

老实说我不太确定。作为缓冲区概念的新手,之前在TCL和Perl中可以直接将变量/标量写入文件句柄。

但我希望在Go中找到类似的功能,能够直接将变量写入文件句柄,而无需考虑缓冲区及其存储的字节数。

这样

import "os/exec"

并不会同时导入 os。你必须添加

import "os"

此外,我想说的是——如果您能详细讲解缓冲区的概念及相关原理……我会很乐意学习缓冲区的工作原理,并在编程中运用更好的方法解决问题。

我找到了一个链接,但它不仅限于Go语言,因为缓冲是一个通用的计算机科学/编程概念:https://www.quora.com/In-C-what-does-buffering-I-O-or-buffered-I-O-mean/answer/Robert-Love-1

这证实了我之前告诉你的内容(请参阅我上面关于bufio的解释)。缓冲区主要用于提高效率。

ln 包含写入文件的字节数,它是一个整数,但你试图将其作为字符串打印。

将最后一行改为(%d 用于整数):

fmt.Printf("%d\n", ln)

你最好参加我的完整课程来系统地学习 Go

package main

import (
  "fmt"
  "os/exec"
  //"io"
)

func main() {
  c,_ := exec.Command("ping","-n","1","8.8.8.8").CombinedOutput()
  //fmt.Printf("%s",c)
  
  f, _ := os.Create("./output.txt")
  defer f.Close()
  
  ln, _ := f.WriteString(c)
  fmt.Printf("%s",ln)
}

不确定为什么我会收到 undefined: os

另外,我阅读了你提供的链接,同时开始查找一些C语言文档,以便学习关于缓冲区的知识。

谢谢

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

您好 Inancgumus, 感谢您提供的这个示例 - 这让我对Go语言中将字符串写入文件的代码概念有了更清晰的理解;不过,您能否展示一个使用缓冲区概念的简单写入示例,这样我就能开始用更好的编程概念和技能来思考了?

我仍然感觉自己在概念理解上有所欠缺,这些概念通常我不会想到,或者是隐藏在背景中的概念。我正在学习Manning出版社William Kennedy所著的《Go实战》一书,但进展缓慢,而我正渴望能更深入地沉浸到Go语言中。

谢谢 RR

我不太明白你想解释什么,但这样做是没必要的:

g := string([]byte(c[:]))

这是因为 c 是一个字节切片([]byte)。所以,直接这样做就足够了:

g := string(c)

但你其实也不需要这样做。f 有一个 Write 方法,它期望接收 []byte 参数,所以你可以直接这样调用:

c, _ := exec.Command("ping", "-n", "1", "8.8.8.8").CombinedOutput()

f, _ := os.Create("./output.txt")
defer f.Close()

ln, _ := f.Write(c)
fmt.Printf("%d", ln)

不过,我还是建议你使用我之前某条消息中发给你的代码。

让我们来看一下 gobyexample 中的示例:

  • ioutil.WriteFile 适用于一次性写入文件的情况

    • 它会创建或截断文件(无法追加内容)
  • os.Create 类似于 os.OpenFile

    • 它会创建文件,如果文件已存在则截断,并返回文件句柄
    • 在底层它会调用 OpenFile,如下所示:
OpenFile(filename, O_RDWR|O_CREATE|O_TRUNC, 0666)
  • f.Write 用于通过字节切片向文件写入内容

  • f.WriteString 用于通过字符串值向文件写入内容

  • bufio.NewWriter 用于需要高效连续写入文件的情况

    • 这是因为它会缓冲你的Write调用(在内存中缓冲),然后在某个时间点将累积的缓冲区实际写入文件。所以它不会每次写入都执行磁盘操作,而是批量写入

实际上,你可以像在 Perl 中那样在 Go 中实现相同的功能。要做到这一点,你需要先打开文件以获取文件句柄,如下所示(这实际上与 go by example 网站上的示例几乎相同):

f, err := os.OpenFile(file, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
  panic(err) // 这里我简化了处理。你可以根据需求自行处理错误。
}
defer f.Close()

然后,你可以像这样直接向文件写入字符串:

f.WriteString("hello world")
f.WriteString("what's up?")

你甚至可以向文件句柄写入格式化消息,如下所示:

fmt.Fprintf(f, "my age is %d\n", 95)

补充说明: 请务必阅读此链接中的文章。

可以按如下方式实现相同功能:

在这个示例中,我将命令的标准输出重定向到我的文件句柄:f

package main

import (
    "log"
    "os"
    "os/exec"
)

func main() {
	f, _ := os.Create("./output.txt")
	defer f.Close()

	c := exec.Command("ping", "-c", "1", "-n", "8.8.8.8")
	c.Stdout = f

	if err := c.Run(); err != nil {
		log.Fatal(err)
	}
}

例如,当命令产生大量输出时,这就是需要使用缓冲的场景之一。你可以轻松地这样实现:

package main

import (
    "bufio"
    "log"
    "os"
    "os/exec"
)

func main() {
  f, _ := os.Create("./output.txt")
  defer f.Close()

  buffered := bufio.NewWriter(f)

  c := exec.Command("ping", "-c", "1", "-n", "8.8.8.8")
  c.Stdout = buffered

  if err := c.Run(); err != nil {
	  log.Fatal(err)
  }

  if err := buffered.Flush(); err != nil {
	  log.Fatal(err)
  }
}

您的解决方案有效,但我还想继续尝试。

我在实验代码时开始尝试不同的方法,以便学习和理解这里发生的情况。从简单的开始,尝试理解返回对象的类型。为此,我使用了以下代码:

fmt.Printf("%T\n",g)

我注意到返回的结果是"[]uint8",这出乎我的意料。后来我在另一个在线论坛找到了这段代码:

:= string([]byte(c[:]))

根据我的研究,"c"是作为字节数组返回的(不确定"数组"这个词是否准确);但我意识到需要将[]uint8转换为字符串,上面的代码实现了这个功能。

我目前的代码如下:

package main

import (
  "fmt"
  "os/exec"
  //"io"
  "os"
)

func main() {
  //var c string
  
  c, _ := exec.Command("ping","-n","1","8.8.8.8").CombinedOutput()
  fmt.Printf("%T\n", c)
  g := string([]byte(c[:]))
  fmt.Printf("%T\n",g)
  
  //fmt.Printf("%s",c)
  
  //g := string(c)
  
  f, _ := os.Create("./output.txt")
  defer f.Close()
  
  ln, _ := f.WriteString(g)
  fmt.Printf("%s",ln)
}

代码似乎可以工作;但我在命令提示符中收到以下输出:

%!s(int=280)

我不确定这个输出是从哪里来的,或者它是如何生成的。是什么导致了这种输出?

在Go语言中,将字符串和变量写入文件有多种直接的方法,无需显式创建缓冲区。以下是几种常见的方式,与Python进行对比,帮助你理解。

1. 使用 os.WriteFile 一次性写入(类似Python的 write 方法)

这种方法简单直接,适用于一次性写入整个字符串或字节数据。

Python示例:

content = "Hello, World!\n"
with open("output.txt", "w") as f:
    f.write(content)

Go示例:

package main

import "os"

func main() {
    content := "Hello, World!\n"
    err := os.WriteFile("output.txt", []byte(content), 0644)
    if err != nil {
        panic(err)
    }
}
  • os.WriteFile 直接写入字节切片,自动处理文件创建和关闭。
  • 权限 0644 表示文件可读写(所有者),只读(其他用户)。

2. 使用 os.Createfmt.Fprintf 写入格式化变量(类似Python的 open 和格式化字符串)

适用于需要格式化输出变量或多次写入的情况。

Python示例:

name = "Alice"
age = 30
with open("output.txt", "w") as f:
    f.write(f"Name: {name}, Age: {age}\n")

Go示例:

package main

import (
    "fmt"
    "os"
)

func main() {
    name := "Alice"
    age := 30

    file, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    _, err = fmt.Fprintf(file, "Name: %s, Age: %d\n", name, age)
    if err != nil {
        panic(err)
    }
}
  • os.Create 创建或截断文件,返回 *os.File
  • fmt.Fprintf 将格式化字符串写入文件,类似Python的 f-stringformat
  • defer file.Close() 确保文件在函数结束时关闭。

3. 使用 bufio.Writer 进行缓冲写入(类似Python的缓冲I/O)

当需要高效写入大量数据时,可以使用缓冲写入器。

Python示例:

lines = ["Line 1\n", "Line 2\n", "Line 3\n"]
with open("output.txt", "w") as f:
    for line in lines:
        f.write(line)

Go示例:

package main

import (
    "bufio"
    "os"
)

func main() {
    lines := []string{"Line 1\n", "Line 2\n", "Line 3\n"}

    file, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    writer := bufio.NewWriter(file)
    for _, line := range lines {
        _, err := writer.WriteString(line)
        if err != nil {
            panic(err)
        }
    }
    writer.Flush() // 确保所有缓冲数据写入文件
}
  • bufio.NewWriter 创建一个缓冲写入器,减少系统调用次数。
  • writer.Flush() 在最后刷新缓冲区,确保所有数据写入文件。

关键点总结:

  • 无需手动缓冲区:在Go中,除非处理大量数据,否则直接使用 os.WriteFilefmt.Fprintf 更简单。
  • 错误处理:Go要求显式处理错误,使用 if err != nil 检查。
  • 文件关闭:使用 defer 确保文件正确关闭,避免资源泄漏。

这些方法覆盖了从简单到高效的场景,你可以根据需求选择。如果写入内容较小,推荐使用 os.WriteFile;如果需要格式化变量,使用 os.Createfmt.Fprintf;对于大量数据,使用 bufio.Writer

回到顶部