Golang文件操作

这篇博客详细介绍了Golang中如何进行文件操作,包括使用os.File进行文件的打开和关闭,使用相关函数读取文件内容,重点讨论了os.OpenFile函数及其多种应用场景,如创建新文件、覆盖已有内容、追加内容、文件拷贝、文件存在性判断以及统计文件字符类型数量等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、打开文件和关闭文件

1)os.File 封装所有文件相关操作

type File struct{
	// 内含隐藏或非导出字段
}

2)相关函数和方法:

func Open(name string) (file *File, err error)

Open 打开一个文件用于读取,如果操作成功,返回的文件对象的方法可以用于读取数据;对应的文件描述符具有O_RDONLY 模式。如果出错,错误底层类型是 *PathError。

func (f *File) Close() error

Close 关闭文件 f ,是文件不能用于读写。它返回可能出现的错误。

3)例:

package main
import(
	"fmt"
	"io"
)
func main(){
	// 打开文件
	file, err := os.Open("d:/1234.txt")
	if err != nil{
		fmt.Println("文件打开错误:%v", err)
	} 
	// 关闭文件
	err = file.Close()
	if err != nil{
		fmt.Println("文件关闭错误:%v", err)
	}
}

2、读取文件内容,

1)在终端显示,带缓冲

使用 os.Openfile closebufio.NewReader()reader.ReadString 函数和方法

package main
import(
	"fmt"
	"io"
	"bufio"
	"os"
)
func main(){
	// 打开文件
	file, err := os.Open("d:/1234.txt")
	if err != nil{
		fmt.Println("文件打开错误:%v", err)
	} 
	
	defer file.Close() // 延时关闭
	
	reader := bufio.NewReader(file)
	for { // 循环读取文件内容
		str, err := reader.ReadString('\n') // 读取到换行就结束
		if err == io.EOF{ // io.EOF 表示文件的末尾
			break
		}
		fmt.Print(str)
	}
	fmt.Println("文件读取结束!")
}

2)使用ioutil 一次将整个文件读入到内存中,适用于文件不大的情况

使用 ioutil.ReadFile 函数和方法

package main
import(
	"fmt"
	"io/ioutil"
)
func main(){
	// 使用 ioutil.ReadFile 一次性将文件读取到位
	file := "d:/test.txt"
	content, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Printf("读取文件错误:%v", err)
	}
	// 把读取到的内容显示到终端
	fmt.Printf("%v", content)	// []byte byte切片类型
	fmt.Printf("%v", string(content))
	// 这里有一点需要注意的!
	// 因为我们没有显式的 Open 文件,因此也不需要显式的 Close 文件
	// 此处的文件操作的 Open 和 Close 已经被封装到了 ReadFile 函数内部
}

3、os.OpenFile 函数

1)基本介绍

func OpenFile(name string, flag int, perm FileMode)(file *File, err error)

name:文件的路径;
flag:文件的打开模式(只读、只写…);
perm:代表文件的模式和权限控制,一般运用在Linux 或者 Unix 里面,在Windows系统下没有。

// 说明:os.OpenFile 是一个更一般性的文件打开函数,它指定的选项(如
// O_RDONLY 等)、指定的模式(如 0666 等)打开指定名称的文件。如果操作
// 成功,返回的文件对象可用于 I/O。如果错误,错误底层类型是 *PathError
// 文件打开模式(可以组合):
const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
    O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
    O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
    O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件
    O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用,文件必须不存在
    O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O
    O_TRUNC  int = syscall.O_TRUNC  // 如果可能,打开时清空文件
)

2)基本应用

① 创建一个新文件,写入内容 5 句 “Hello, World!”

创建文件加撰写内容

package main
import (
	"fmt"
	"bufio"
	"os"
)
func main() {
	filePath := "d:/1234.txt"
	file, err := os.OpenFile(filePath, os.O_WRONLY | os.CREATE, O666)
	if err != nil {
		fmt.Printf("打开文件错误%v\n", err)
		return
	}
	
	defer file.Close() // 及时关闭 file 句柄
	
	str := "Hello, World!\n"
	writer := bufio.NewWriter(file)
	for i := 0;  i < 5; i++ {
		writer.WriteString(str)
	}
	// 因为 writer 是带缓存,因此在调用 WriterString 方法时,其实
	// 内容时先写到缓存中的,所以需要调用 Flush 方法,将缓冲的数据
	// 真正写入到文件中,否则文件中会没有数据!!!
	writer.Flush()
}
func NewWriter(w io.Writer) *Writer
// NewWriter 创建一个具有默认大小缓冲、写入 w 的 *Writer
func (b *Writer) WriteString(s string)(nn int, err error)
// WriteString 写入一个字符串。返回写入的字节数。如果返回值 nn < len(s),还会返回一个错误说明原因。

② 打开一个存在的文件,将原来的内容覆盖成新的内容 10句 “武林至尊,宝刀屠龙,号令天下,莫敢不从!”

覆盖

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	filePath := "d:/1234.txt"
	file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_TRUNC, 0666)
	if err != nil {
		fmt.Printf("文件打开错误:%v\n", err)
		return
	}
	derfer file.Close()
	
	str := "武林至尊,宝刀屠龙,号令天下,莫敢不从!"
	
	writer := bufio.NewWriter(file)
	for i := 0; i < 10; i++ {
		writer.WriteString(str)
	}
	writer.Flush()
}

③ 打开一个存在的文件,在原来的内容上追加五句“醉后不知天在水,满船清梦压星河。”

追加

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	filePath := "d:/1234.txt"
	file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_APPEND, 0666)
	if err != nil {
		fmt.Printf("文件打开错误:%v\n", err)
		return
	}
	derfer file.Close()
	
	str := "醉后不知天在水,满船清梦压星河。"
	
	writer := bufio.NewWriter(file)
	for i := 0; i < 5; i++ {
		writer.WriteString(str)
	}
	writer.Flush()
}

④ 打开一个存在的文件,在原来的内容显示在终端,然后又追加五句“春风得意马蹄疾,一日看尽长安花。”

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	filePath := "d:/1234.txt"
	file, err := os.OpenFile(filePath, os.O_RDWR| os.O_APPEND, 0666)
	if err != nil {
		fmt.Printf("文件打开错误:%v\n", err)
		return
	}
	derfer file.Close()
	
	// 先读取原来的内容显示在终端
	reader := bufio.NewReader(file)	
	for {
		str, err := reader.ReadString('\n')
		if err == io.EOF {	// 如果读取文件的末尾
			break
		}
		fmt.Print(str) // 显示到终端
	}
	
	str := "春风得意马蹄疾,一日看尽长安花。"
	writer := bufio.NewWriter(file)
	for i := 0; i < 5; i++ {
		writer.WriteString(str)
	}
	writer.Flush()
}
func NewReader(rd io.Reader) *Reader
// NewReader创建一个具有默认大小缓冲、从r读取的*Reader。
func (b *Reader) ReadString(delim byte) (line string, err error)
/* 
ReadString读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的字符串。
如果ReadString方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误
(一般是io.EOF)。当且仅当ReadString方法返回的切片不以delim结尾时,会返回一个非nil的
错误。
*/
var EOF = errors.New("EOF")
// EOF当无法得到更多输入时,Read方法返回EOF。当函数一切正常的到达输入的结束时,就应返
// 回EOF。如果在一个结构化数据流中EOF在不期望的位置出现了,则应返回错误ErrUnexpectedEOF
// 或者其它给出更多细节的错误。

⑤ 编写一个程序,将一个文件的内容,写入到另一个文件。注:这两个文件已经存在了。

使用 ioutil.ReadFileioutil.WriteFile 完成写文件的任务

func ReadFile(filename string) ([]byte, error)
// ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的
// errnil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报
// 告的错误。
func WriteFile(filename string, data []byte, perm os.FileMode) error
// 函数向filename指定的文件中写入数据。如果文件不存在将按给出的权限创建文件,
// 则在写入数据之前清空文件。
package main

import (
	"fmt"
	"io/ioutil"
)
func main() {
	// 将 d:/1234.txt 文件内容导入到 e:/abcd.txt
	// 1. 首先将 d:/1234.txt 内容读取到内存
	// 2. 将读取到的内容写入 e:/abcd.txt
	filePath1 := "d:/1234.txt"
	filePath2 := "e:/abcd.txt"
	data, err := ioutil.ReadFile(filePath1)
	if err != nil {
		fmt.Printf("文件读取错误:%v\n", err)
		return
	}

	err = ioutil.WriteFile(filePath2, data, 0666)
	if err != nil {
		fmt.Printf("写入错误:%v\n", err)
	}
}

⑥ 判断文件是否存在

使用 os.Stat() 函数返回的错误值进行判断:
1) 如果返回的错误为 nil,说明文件或者文件夹存在;
2) 如果返回的错误类型使用 os.IsNotExist() 判断为 true,说明文件或者文件夹不存在;
3) 如果返回的错误为其他类型,则不确定是否存在。

package main

import (
	"fmt"
	"os"
)

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil { //文件或者目录存在
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}

func main() {
	filePath1 := "e:/1234.txt"
	filePath3 := "e:/1abc.txt"
	fmt.Println(PathExists(filePath3))
	a := fmt.Sprintln(PathExists(filePath1))
	fmt.Println(a)

}

⑦ 拷贝文件

将一个文件拷贝到另外一个文件里面 使用 io 包

func Copy(dst Writer, src Reader)(written int64, err,error)
// Copy 函数由 io 包提供
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
)

// 自己编写一个函数,接收两个文件路径 srcFileName dstFileName
func CopyFile(dstFileName string, srcFileName string) (written int64, err error) {
	srcFile, err := os.Open(srcFileName)
	if err != nil {
		fmt.Printf("打开错误:%v\n", err)
	}

	defer srcFile.Close()

	// 通过 srcfile,获取到 Reader
	reader := bufio.NewReader(srcFile)
	// 打开 dstFileName
	dstFile, err := os.OpenFile(dstFileName, os.O_WRONLY|os.O_CREATE, 0666)
	if err != nil {
		fmt.Printf("打开错误:%v\n", err)
		return
	}
	
	// 通过 dstFile,获取到 Writer
	writer := bufio.NewWriter(dstFile)
	defer dstFile.Close()

	return io.Copy(writer, reader)
}

func main() {
	// 将 d:/flower.jpg 文件拷贝到 e:/abc.jpg
	// 调用 CopyFile 完成文件拷贝
	srcFile := "d:/flower.jpg"
	dstFile := "e:/abc.jpg"
	_, err := CopyFile(dstFile, srcFile)
	if err == nil {
		fmt.Printf("拷贝完成!\n")
	} else {
		fmt.Printf("拷贝错误:%v\n", err)
	}
}

⑧ 统计一个文件中英文、数字、空格和其他字符数量

package main
import (
	"fmt"
	"os"
	"io"
	"bufio"
)

// 定义一个结构体,用于保存统计结果
type CharCount struct{
	ChCount int	// 记录英文个数
	NumCount int // 记录数字的个数
	SpaceCount int // 记录空格的个数
	OtherCount int // 记录其他字符的个数
}

func main(){
	/*
	思路:打开一个文件,创建一个Reader
	每读取一行,就去统计该行有多少个英文、数字、空格和其他字符
	然后将结果保存到一个结构体
	*/
	fileName := "e:/1234.txt"
	file, err := os.Open(fileName)
	if err != nil {
		fmt.Printf("打开文件错误:%v\n", err)
		return
	}
	defer file.Close()
	// 定义个 CharCount 实例
	var count CharCount
	// 创建一个 Reader
	reader := bufio.NewReader(file)

	// 开始循环读取 fileName 的内容
	for {
		str, err := reader.ReadString('\n')
		if err == io.EOF{
			break
		}
		// 为了兼容中文字符,可以将str 转换成 []rune
		str = []rune(str)
		// 遍历 str, 进行统计
		for _, v := range str {
			
			switch {
				case v >= 'a' && v <= 'z':
					fallthrough // 穿透
				case v >= 'A' && v <= 'Z':
					count.ChCount++
				case v == '' && v <= '\t':
					count.SpaceCount++
				case v == '0' && v <= '9':
					count.NumCount++
				default:
					count.OtherCount++
			}
		}
	}
	// 输出统计结果看看是否正确
	fmt.Printf("字符的个数 = %v 数字的个数 = %v 空格的个数 = %v 其他字符的个数 = %v",
	count.ChCount, count.NumCount, count.SpaceCount, count.OtherCount)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值