Golang文件IO操作基础示例
Go语言凭借其简洁的语法和强大的标准库,在数据处理领域应用广泛。文件输入输出(IO)是编程中最常见的操作之一,标准库中的 os、io 和 bufio 等包为开发者提供了高效且灵活的工具。本文将通过一系列基础示例,逐步演示如何安全地打开、读取、写入和关闭文件,并讨论处理大文件时的流式技巧。
1. 打开文件与错误处理
使用 os.Open() 函数可以打开一个文件以供读取。该函数会返回一个文件指针和可能出现的错误。在Go语言中,明确的错误处理是必须遵守的习惯。同时,务必利用 defer 语句确保文件在函数退出时被关闭,以释放系统资源。
package main
import (
"fmt"
"os"
)
func main() {
// 以只读方式打开文件
file, err := os.Open("data.txt")
if err != nil {
fmt.Println("打开文件失败:", err)
return
}
// 延迟关闭文件,确保资源最终被释放
defer file.Close()
fmt.Println("文件打开成功")
}2. 读取文件内容
Go提供了多种读取文件的方法,开发者应根据数据规模和需求选择合适的方式。对于小文件,可以使用 io.ReadAll 一次性读取全部内容(Go 1.16及以上版本)。对于需要逐行处理的大文件,bufio.Scanner 是一个内存高效的选择。下面的示例展示了如何通过扫描器逐行读取并输出内容。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
file, err := os.Open("data.txt")
if err != nil {
fmt.Println("错误:", err)
return
}
defer file.Close()
// 创建一个扫描器,默认按行分割
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text() // 获取当前行的文本
fmt.Println(line)
}
// 检查扫描过程中是否发生错误
if err := scanner.Err(); err != nil {
fmt.Println("读取过程中发生错误:", err)
}
}3. 写入文件
写入操作需要以适当的模式打开文件。使用 os.Create() 会创建一个新文件,如果文件已存在则会截断其内容。更复杂的模式可以通过 os.OpenFile() 指定。写入字符串可以使用便捷的 file.WriteString() 方法。
package main
import (
"fmt"
"os"
)
func main() {
// 创建新文件,若同名文件已存在则清空
file, err := os.Create("output.txt")
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()
// 写入文本内容
written, err := file.WriteString("Hello, Go IO!\n")
if err != nil {
fmt.Println("写入失败:", err)
return
}
fmt.Printf("写入操作成功完成,共写入 %d 个字节\n", written)
}4. 利用io.Copy实现文件复制
io.Copy 是一个非常有用的函数,它可以直接将数据从源复制到目标,内部处理了缓冲和读取-写入的循环细节。下面的例子演示了如何使用它来完整复制一个文件。
package main
import (
"fmt"
"io"
"os"
)
func main() {
srcFile, err := os.Open("source.txt")
if err != nil {
fmt.Println("打开源文件失败:", err)
return
}
defer srcFile.Close()
dstFile, err := os.Create("destination.txt")
if err != nil {
fmt.Println("创建目标文件失败:", err)
return
}
defer dstFile.Close()
// 直接调用io.Copy并获取复制的字节数
bytesCopied, err := io.Copy(dstFile, srcFile)
if err != nil {
fmt.Println("复制过程中发生错误:", err)
return
}
fmt.Printf("文件复制成功,总计复制 %d 字节\n", bytesCopied)
}5. 综合示例:处理大型文本文件
对于体积较大的文件,应避免一次性将所有数据加载到内存中。采用缓冲读写和流式处理是更安全的策略。在下面的示例中,我们使用 bufio.Reader 从输入文件逐行读取,用 bufio.Writer 将处理后的行写入输出文件,并为每一行添加行号。这样,即使源文件很大,程序的内存占用量也保持稳定。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
inputFile, err := os.Open("large.txt")
if err != nil {
fmt.Println("错误:", err)
return
}
defer inputFile.Close()
outputFile, err := os.Create("processed.txt")
if err != nil {
fmt.Println("错误:", err)
return
}
defer outputFile.Close()
// 创建带缓冲的读取器和写入器
reader := bufio.NewReader(inputFile)
writer := bufio.NewWriter(outputFile)
// 确保所有缓冲数据在程序结束前写入文件
defer writer.Flush()
lineNumber := 0
for {
// 读取直到遇到换行符\n
line, err := reader.ReadString('\n')
if err != nil {
break // 文件末尾或出错时跳出循环
}
lineNumber++
// 构造带行号的新行,并写入缓冲区
processedLine := fmt.Sprintf("%d: %s", lineNumber, line)
writer.WriteString(processedLine)
}
fmt.Printf("处理完成,共读取并处理了 %d 行文本\n", lineNumber)
}总结
掌握文件IO操作是使用Go进行系统编程和数据处理的重要一步。本文从基本的结构讲起,涵盖了打开、读取、写入和复制文件的多种技术。关键点在于始终检查错误、使用 defer 管理资源关闭,以及根据文件大小灵活选择读取策略(一次性加载或流式处理)。标准库中的 io 和 bufio 包提供了清晰而强大的抽象,基于这些基础示例,开发者可以轻松构建出稳定高效的文件处理工具。