Golang文件操作
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.Open; file close; bufio.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.ReadFile 、 ioutil.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)
}