本文为转载,原文:Golang 学习笔记(08)—— 文件操作
path
在path包中封装了一些路径相关的操作,在开始接触文件操作之前,我们先看看路径的相关函数。在Linux中,路径的格式为/user/bin路径中分隔符是/;Windows中的路径格式为c:\Windows路径中的分隔符是\。而在go中只认/。所以在windows中,需要把path中的\替换为/。
func Base
func Base(path string) string
Base函数返回路径的最后一个元素。在提取元素前会求掉末尾的斜杠。 如果路径是"",会返回"."; 如果路径是只有一个斜杆构成,会返回"/"
func Clean
func Clean(path string) string
Clean函数通过单纯的词法操作返回和path代表同一地址的最短路径。
它会不断的依次应用如下的规则,直到不能再进行任何处理:
- 将连续的多个斜杠替换为单个斜杠
- 剔除每一个.路径名元素(代表当前目录)
- 剔除每一个路径内的..路径名元素(代表父目录)和它前面的非..路径名元素
- 剔除开始一个根路径的..路径名元素,即将路径开始处的"/.."替换为"/"
只有路径代表根地址"/"时才会以斜杠结尾。如果处理的结果是空字符串,Clean会返回"."。
func Dir
func Dir(path string) stringDir
返回路径除去最后一个路径元素的部分,即该路径最后一个元素所在的目录。在使用Split去掉最后一个元素后,会简化路径并去掉末尾的斜杠。如果路径是空字符串,会返回".";如果路径由1到多个斜杠后跟0到多个非斜杠字符组成,会返回"/";其他任何情况下都不会返回以斜杠结尾的路径。
func Ext
func Ext(path string) string
Ext函数返回path文件扩展名。返回值是路径最后一个斜杠分隔出的路径元素的最后一个'.'起始的后缀(包括'.')。如果该元素没有'.'会返回空字符串。
func IsAbs
func IsAbs(path string) bool
IsAbs返回路径是否是一个绝对路径。
func Split
func Split(path string) (dir, file string)
Split函数将路径从最后一个斜杠后面位置分隔为两个部分(dir和file)并返回。如果路径中没有斜杠,函数返回值dir会设为空字符串,file会设为path。两个返回值满足path == dir+file。
func Join
func Join(elem ...string) string
Join函数可以将任意数量的路径元素放入一个单一路径里,会根据需要添加斜杠。结果是经过简化的,所有的空字符串元素会被忽略。
示例
package main
import (
"path"
"fmt"
)
func main(){
fmt.Println("path.Base: ",path.Base("C:/Users/zzc/go/src/channelDemo"))
fmt.Println("path.Clean: ",path.Clean("C:/Users/zzc/./go///src/../../channelDemo/"))
fmt.Println("path.Ext: ",path.Ext("C:/Users/zzc/go/src/channelDemo/main.go"))
fmt.Println("path.Dir: ",path.Dir("C:/Users/zzc/go/src/channelDemo/main.go"))
fmt.Println("path.IsAbs: ",path.IsAbs("C:/Users/zzc/go/src/channelDemo/main.go"))
dir, file := path.Split("C:/Users/zzc/go/src/channelDemo/main.go")
fmt.Println("path.Split: ",dir, file)
fmt.Println("path.Join: ",path.Join("c:/Users", "zzc", "go", "src"))
}
文件读写
在os包中提供了一下文件操作的函数。
创建文件
- Create
func Create(name string) (file *File, err error)
Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会截断它(为空文件)。如果成功,返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。如果出错,错误底层类型是*PathError。
例如:
file, err := os.Create("d:/my.txt")
打开文件
open
func Open(name string) (file *File, err error)
Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。
OpenFile
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError
。
name
: 要打开或要创建的文件名
flag
: 是打开文件的方式,可以取以下值:
- O_RDONLY:以只读的方式打开
- O_WRONLY:以只写的方式打开
- O_RDWR:以读写的方式打开
- O_APPEND:以追加方式打开文件,写入的数据将追加到文件尾
- O_CREATE:当文件不存在时创建文件
- O_EXCL:与O_CREATE一起使用,当文件存在时Open失败
- O_SYNC:以同步方式打开文件。每次write系统调用后等等待实际的物理I/O完成后才返回,默认(不使用该标记)是使用缓冲的,也就是说每次的写操作是写到系统内核缓冲区中,等系统缓冲区满后才写到实际存储设备中。
- O_TRUNC:如果文件已存在,打开是会清空文件内容。必须于O_WRONLY或O_RDWR配合使用。截断文件,需要有写的权限。
FileMode
: 是文件的权限,只有在文件不存在,新建文件时该参数才有效。用来指定新建的文件的权限。必须跟O_CREATE配合使用。
写文件
Write
func (f *File) Write(b []byte) (n int, err error)
Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
WriteString
func (f *File) WriteString(s string) (ret int, err error)
WriteString类似Write,但接受一个字符串参数。
WriteAt
func (f *File) WriteAt(b []byte, off int64) (n int, err error)
WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。
读文件
Read
func (f *File) Read(b []byte) (n int, err error)
Read方法从f中读取最多len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值err为io.EOF。
ReadAt
func (f *File) ReadAt(b []byte, off int64) (n int, err error)
ReadAt从指定的位置(相对于文件开始位置)读取len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。当n
其他
Close
func (f *File) Close() error
Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。
Seek
func (f *File) Seek(offset int64, whence int) (ret int64, err error)
Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。
whence在系统中定义的有常量:
SEEK_SET:0
SEEK_CUR:1
SEEK_END:2
例子
package main
import (
"io"
"fmt"
"os"
)
func main(){
testio()
}
func testio(){
//若文件不存在则创建文件,以append方式打开
file, err := os.OpenFile("d:/test.txt", os.O_CREATE|os.O_APPEND, 0666)
if err != nil{
fmt.Println(err)
return
}
defer file.Close() //关闭文件
file.WriteString("i am chain ") //写入文件
buf := make([]byte, 1024)
var str string
file.Seek(0, os.SEEK_SET) //重置文件指针
//读取文件
for {
n, ferr := file.Read(buf)
if ferr != nil && ferr != io.EOF{
fmt.Println(ferr.Error())
break
}
if n == 0{
break
}
str += string(buf[0:n])
}
fmt.Println("file content: ", str)
}
执行两次之后的结果如下图
ioutil
在ioutil中封装了一些函数,让IO操作更简单方便
ReadAll
func ReadAll(r io.Reader) ([]byte, error)
ReadAll从r读取数据直到EOF或遇到error,返回读取的数据和遇到的错误。成功的调用返回的err为nil而非EOF。因为本函数定义为读取r直到EOF,它不会将读取返回的EOF视为应报告的错误。
ReadFile
func ReadFile(filename string) ([]byte, error)
ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报告的错误。
WriteFile
func WriteFile(filename string, data []byte, perm os.FileMode)
error函数向filename指定的文件中写入数据。如果文件不存在将按给出的权限创建文件,否则在写入数据之前清空文件。
例子
package main
import (
"io"
"io/ioutil"
"fmt"
"os"
)
func main(){
testioutil()
}
func testioutil(){
str := "i am chain, i am a good boy. "
//写入数据
err := ioutil.WriteFile("d:/a.txt",[]byte(str), 0666)
if err != nil{
fmt.Println(err.Error())
}else{
fmt.Println("write success!")
}
//通过readfile函数读取数据
buf1, err1 := ioutil.ReadFile("d:/a.txt")
if err1 != nil{
fmt.Println(err1.Error())
}else{
fmt.Println("Read File: ", string(buf1))
}
//通过readall读取数据
f, err2 := os.OpenFile("d:/a.txt", os.O_RDONLY, 0666)
if err2 != nil{
fmt.Println(err2.Error())
return
}
defer f.Close()
buf2, err3 := ioutil.ReadAll(f)
if err3 != nil{
fmt.Println(err3.Error())
}else{
fmt.Println("read all: ", string(buf2))
}
}
目录操作
os/Readdir
func (f *File) Readdir(n int) (fi []FileInfo, err error)
Readdir读取目录f的内容,返回一个有n个成员的[]FileInfo,这些FileInfo是被Lstat返回的,采用目录顺序。对本函数的下一次调用会返回上一次调用剩余未读取的内容的信息。
如果n>0,Readdir函数会返回一个最多n个成员的切片。这时,如果Readdir返回一个空切片,它会返回一个非nil的错误说明原因。如果到达了目录f的结尾,返回值err会是io.EOF。
如果n<=0,Readdir函数返回目录中剩余所有文件对象的FileInfo构成的切片。此时,如果Readdir调用成功(读取所有内容直到结尾),它会返回该切片和nil的错误值。如果在到达结尾前遇到错误,会返回之前成功读取的FileInfo构成的切片和该错误。
package main
import (
"fmt"
"os"
)
func main(){
f, err := os.OpenFile("D:/code/", os.O_RDONLY, 0666)
if err != nil{
fmt.Println(err.Error())
return
}
arrFiles, err1:=f.Readdir(0)
if err1 != nil{
fmt.Println(err1.Error())
return
}
for k, v := range arrFiles{
fmt.Println(k, "\t", v, "\t", v.IsDir())
}
}
ioutil/ReadDir
func ReadDir(dirname string) ([]os.FileInfo, error)
返回dirname指定的目录的目录信息的有序列表。
package main
import (
"io"
"io/ioutil"
"fmt"
)
func main(){
arrFiles, err1 := ioutil.ReadDir("D:/code/")
if err1 != nil{
fmt.Println(err1.Error())
return
}
for k, v := range arrFiles{
fmt.Println(k, "\t", v, "\t", v.IsDir())
}
}
gob序列化
序列化就是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。之后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。
gob是go中特有的序列化技术,它支持除interface,function,channel外的所有go数据类型。序列化用Encoder,反序列化用Decoder。
package main
import (
"encoding/gob"
"os"
"fmt"
)
type Student struct{
Name string
Age int
}
func main(){
stu := &Student{"chain", 23}
f, err := os.Create("d:/stu.txt")
if err != nil{
fmt.Println(err.Error())
return
}
defer f.Close()
//创建Encoder对象
encode := gob.NewEncoder(f)
//将stu序列化到f中
encode.Encode(stu)
//重置文件指针
f.Seek(0, os.SEEK_SET)
//创建decoder对象
decoder := gob.NewDecoder(f)
var s1 Student
//反序列化对象
decoder.Decode(&s1)
fmt.Println(s1)
}
完
转载请注明出处
Golang 学习笔记(08)—— 文件操作
目录
上一节:Golang 学习笔记(07)—— 错误及异常处理
下一节:Golang 学习笔记(09)—— json和xml解析