一、文件基本介绍
- 文件是数据源(保存数据的地方)的一种。
- 文件在程序中是以流的形式来操作的。
- 流:数据在数据源(文件)和程序(内存)之间经历的路径。
- 输入流:读文件;输出流:写文件。
- os.File封装所有文件相关操作,File是一个结构体。
二、读文件常用操作
//读取和关闭文件
package main
import(
"fmt"
"os"
)
func main() {
//打开文件
file,err := os.Open("e:/test.txt") //打开E盘里的test文件
if err !=nil {
fmt.Println("open file err = ",err) //如果err!=nil,意味着没打开文件
}
//输出文件,查看内容
fmt.Printf("file=%v",file)
//关闭文件
err = file.Close()
if err !=nil {
fmt.Println("close file err = ",err)
}
}
file=&{0xc00011a780} //表明文件返回一个指针
1.读取下面test.txt文件内容并显示在终端(带缓冲区的方法)【使用os.Open, file.Close, bufio.NewReader(), reader.ReadString 函数和方法】
package main
import(
"fmt"
"os"
"bufio"
"io"
)
func main() {
//打开文件
file,err := os.Open("e:/test.txt")
if err !=nil {
fmt.Println("open file err = ",err)
}
defer file.Close() //当函数退出时,可以及时关闭file句柄,防止内存泄漏
//创建一个 *Reader,带缓冲,默认缓冲区为4096
reader := bufio.NewReader(file) //返回 *Reader
//循环读取文件内容
for {
str, err := reader.ReadString('\n') //读到一个换行就结束一次
//输出内容
fmt.Print(str)
if err == io.EOF { //io.EOF表示文件的末尾
break
}
}
}
输出结果:
2.对于如上述文件内存不大的情况,可以使用ioutil一次将整个文件读入到内存中。【相关方法和函数:ioutil.ReadFile】
package main
import(
"fmt"
"io/ioutil"
)
func main() {
//使用 ioutil.ReadFile 一次性将文件读取到位
file := "e:/test.txt"
content,err := ioutil.ReadFile(file)
if err!=nil {
fmt.Printf("read file err=%v",err)
}
fmt.Printf("%v",string(content))
//因为没有显式的Open文件,因此也不需要显式的Close文件
//文件的Open和Close被封装到 ReadFile 内部
}
//与上一个方法输出结果一致
三、写文件常用操作
func OpenFile(name string,flag int,perm FileMode) (file *File,err error)
第二个参数(文件打开模式)的几种方式:
第三个参数(FileMode)代表文件的模式和权限位。在window系统无效。
写文件基本应用实例:
1.创建一个新文件,写入内容五句“hello golang”
package main
import(
"fmt"
"bufio"
"os"
)
func main() {
filePath := "e:/abc.txt"
file,err := os.OpenFile(filePath,os.O_WRONLY|os.O_CREATE,0666)
if err != nil {
fmt.Printf("open file err=%v\n",err)
return
}
//及时关闭file句柄
defer file.Close()
str := "hello,Golang!\n"
//写入时使用带缓冲的 *Writer
writer := bufio.NewWriter(file)
for i :=0;i<5;i++ {
writer.WriteString(str)
}
//因为writer是带缓存的,在调用WriteString方法时,内容是先写入到缓存的
//因此需要调用 Flush 方法将缓冲的数据写入磁盘
//否则文件中会没有数据
writer.Flush()
}
2.打开一个存在的文件,将原来的内容覆盖成新的10句内容“have a good day!”
package main
import(
"fmt"
"bufio"
"os"
)
func main() {
filePath := "e:/abc.txt"
file,err := os.OpenFile(filePath,os.O_WRONLY|os.O_TRUNC,0666) //清空文件
if err != nil {
fmt.Printf("open file err=%v\n",err)
return
}
//及时关闭file句柄
defer file.Close()
str := "have a good day!\n"
//写入时使用带缓冲的 *Writer
writer := bufio.NewWriter(file)
for i :=0;i<10;i++ {
writer.WriteString(str)
}
writer.Flush()
}
3.打开一个存在的文件,在原来的内容上追加内容“ABXCDEFGHIJKLMN”
package main
import(
"fmt"
"bufio"
"os"
)
func main() {
filePath := "e:/abc.txt"
file,err := os.OpenFile(filePath,os.O_WRONLY|os.O_APPEND,0666) //清空文件
if err != nil {
fmt.Printf("open file err=%v\n",err)
return
}
//及时关闭file句柄
defer file.Close()
str := "ABXCDEFGHIJKLMN\n"
//写入时使用带缓冲的 *Writer
writer := bufio.NewWriter(file)
writer.WriteString(str)
writer.Flush()
}
4.将 e:/abc.txt 文件内容导入到 e:/aaa.txt
package main
import(
"fmt"
"io/ioutil"
)
func main() {
//1.首先将 e:/abc.txt 内容读取到内存
//2.将读取到的内存写入 e:/aaa.txt
file1Path := "e:/abc.txt"
file2Path := "e:/aaa.txt"
data,err := ioutil.ReadFile(file1Path)
if err != nil {
//说明读取文件有错误
fmt.Printf("read file err=%v\n",err)
return
}
err2 := ioutil.WriteFile(file2Path,data,0666)
if err2 != nil {
fmt.Printf("write file err=%v\n",err)
}
}
四、判断文件或目录存在
golang判断文件或文件夹是否存在的方法为使用os.Stat()函数返回的错误值进行判断;
1)如果返回的错误为nil,说明文件或文件夹存在。
2)如果返回的错误类型使用os.lsNotExist()判断为true,说明文件或文件夹不存在。
3)如果返回的错误为其它类型,则不确定是否在存在。
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 Copy( dst Writer, src Reader) (written int64,err error)
package main
import(
"fmt"
"bufio"
"os"
"io"
)
//编写函数,接收两个文件路径
func CopyFile(dstFileName string,srcFileName string)(written int64,err error) {
srcFile,err := os.Open(srcFileName)
if err != nil {
fmt.Printf("open file err=%v",err)
}
defer srcFile.Close()
//通过srcFile,获取到Reader
reader := bufio.NewReader(srcFile)
//使用OpenFile方式打开目标文件 dstFile
dstFile,err := os.OpenFile(dstFileName,os.O_WRONLY|os.O_CREATE,0666)
if err != nil {
fmt.Printf("open file err=%v",err)
return
}
//通过dstFile,获取到 Writer
writer := bufio.NewWriter(dstFile)
defer dstFile.Close()
return io.Copy(writer,reader)
}
func main() {
//将 d:/run.jpg 文件拷贝到 e:/ccc.jpg
srcFile := "d:/run.jpg"
dstFile := "e:/ccc.jpg"
_,err := CopyFile(dstFile,srcFile)
if err == nil {
fmt.Println("拷贝完成")
} else {
fmt.Printf("拷贝错误,err=%v",err)
}
}
输出结果:
拷贝完成
使用这种拷贝方式,调用的函数中有缓冲功能,可以拷贝大文件。
六、文件编程应用实例
统计一个test文件中含有的英文、数字、空格及其它字符数量。
package main
import(
"fmt"
"os"
"io"
"bufio"
)
//定义一个结构体,用于保存统计结果
type CharCount struct {
ChCount int //记录英文个数
NumCount int //记录数字个数
SpaceCount int //记录空格个数
OtherCount int //记录其它字符个数
}
func main() {
//1.打开文件,创一个 *Reader
//2.每读取一行,就去统计该行有多少个 英文、数字、空格和其它字符
//3.将结果保存到一个结构体中
fileName := "e:/test.txt"
file,err := os.Open(fileName)
if err != nil {
fmt.Printf("open file err=%v\n",err)
return
}
defer file.Close()
//定义结构体实例
var count CharCount
reder := bufio.NewReader(file)
//循环读取文件内容
for{
str,err := reder.ReadString('\n')
//遍历str,进行统计
for _,v := range str {
switch {
case v>='a'&& v<='z':
fallthrough //穿透
case v>='A'&& v<='Z':
count.ChCount++
case v>='0'&&v<='9':
count.NumCount++
case v==' '|| v=='\t':
count.SpaceCount++
default:
count.OtherCount++
}
}
if err == io.EOF {
break
}
}
fmt.Printf("字符个数=%v 数字个数=%v 空格个数=%v 其它字符个数=%v",
count.ChCount,count.NumCount,count.SpaceCount,count.OtherCount)
}
输出结果:
字符个数=24 数字个数=23 空格个数=15 其它字符个数=22