5-0. 文件操作
- 文件操作设计的I/O操作库
- io – 提供基本的接口
- io/ioutil – 封装了一些常用的接口
- fmt – 实现格式化IO. 类似c语言中的printf和scanf
- bufio – 实现缓存I/O
io/ioutil
-
读取文件目录
ReadDir()
, 返回一个列表[]os.FileInfo
, 列表中包含指定目录的目录信息1 2 3 4 5 6 7 8
type FileInfo interface{ Name() string // 文件名称 Size() int64 // 文件大小 Mode() FileMode //打开模式 ModTime() time.Time //文件修改时间 IsDIr() bool // 是否是目录 Sys() interface{} // 基础数据源 }
-
demo : 查看文件夹中所有文件, 并输出文件名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
package main import ( "fmt" "io/ioutil" ) func getFileName(filePath string) { dir, err := ioutil.ReadDir(filePath) if err != nil { fmt.Println(err) } for _,file := range dir{ fileName := file.Name() fmt.Println(fileName) } } func main() { filePath := "../../" getFileName(filePath) }
-
path/filepath
-
Walk() 获取目录下所有文件和文件夹
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
package main import ( "fmt" "io/fs" "path/filepath" ) //walk() 获取指定目录下的所有文件和文件夹 func WalkDir(dirPath string) { err := filepath.Walk(dirPath, func(path string, info fs.FileInfo, err error) error { if info ==nil{ return err } if info.IsDir(){ return nil } fmt.Println(path) return nil }) if err != nil{ fmt.Printf("filepath.Walk() returned %v\n",err) } } func main() { WalkDir("./") }
OS
- os.Makedir创建文件夹,需要指定权限
- 创建文件夹没有权限会报错
- os.MkdirAll创建文件夹 , 需要制定权限
- 创建文件夹, 不存在就创建, 存在返回nil
- os.Remove() 删除指定文件夹, 非空不能删除
- os.RemoveAll() 删除指定文件夹, 非空也删除
- os.OpenFile() 创建/读取文件
- os.Open() 读文件
- os.ModePerm 返回值:
-rwxrwxrwx
,类似0777
0.0.0.0.1 os.Open 与读的方式
f ,e := os.OpenFile(“data.csv”)
0.0.0.0.2 os.OpenFile 读写方式
f ,e := os.OpenFile(“data.csv”, os.O_CREATE|os.O_RDWR, 0644)
0.1 FileInfo
FileInfo 接口中定义了 File 信息相关的方法。
|
|
0.2 权限
至于操作权限 perm,除非创建文件时才需要指定,不需要创建新文件时可以将其设定为0。虽然 Golang 语言给 perm 权限设定了很多的常量,但是习惯上也可以直接使用数字,如 0666 (具体含义和 Unix 系统的一致)。 权限控制:
|
|
0.3 创建文件夹
- os.MkDir(“dirName”,os.ModePerm ),创建一层
- os.MkDirAll(“dirName”,os.ModePerm ),可以创建多层
0.4 创建文件
- os.Create(),创建文件
- 采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会替换它(为空文件)
0.5 打开/关闭文件
-
os.Open(fileName) 只读
-
os.OpenFile(filename,mode,perm) –文件名称|文件的打开方式|文件的权限
1
file4,err := os.OpenFile(fileName1,os.O_RDONLY|os.O_WRONLY,os.ModePerm)
-
第一个参数:文件名称
-
第二个参数:文件的打开方式
模式 含义 os.O_WRONLY 只写 os.O_CREATE 创建文件 os.O_RDONLY 只读 os.O_RDWR 读写 os.O_TRUNC 清空 os.O_APPEND 追加 1 2 3 4 5 6 7 8 9 10 11 12 13 14
const ( // Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified. O_RDONLY int = syscall.O_RDONLY // open the file read-only. O_WRONLY int = syscall.O_WRONLY // open the file write-only. O_RDWR int = syscall.O_RDWR // open the file read-write. // The remaining values may be or'ed in to control behavior. O_APPEND int = syscall.O_APPEND // append data to the file when writing. O_CREATE int = syscall.O_CREAT // create a new file if none exists. O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist. O_SYNC int = syscall.O_SYNC // open for synchronous I/O. O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened. )
-
第三个参数:文件的权限:文件不存在创建文件,需要指定权限
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
package main import ( // "fmt" "fmt" "os" ) func main() { file, err := os.Open("word.txt") // 读取文件 if err != nil { fmt.Println("error:", err) return } defer file.Close() fileinfo, err := file.Stat() if err != nil { fmt.Println(err) return } fileSize := fileinfo.Size() // 文件大小 buffer := make([]byte, fileSize) bytesread, err := file.Read(buffer) //获取文件内容 if err != nil { fmt.Println("err::", err) } fmt.Println("bytes read: ", bytesread) fmt.Println("bytestream to string: ", string(buffer)) }
-
-
file.Close() 关闭文件
0.6 创建/删除文件/目录
- os.Create(),创建文件
- 采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会替换它(为空文件)
- 删除文件 os.Remove()
- 删除文件夹 os.RemoveAll()
|
|
0.7 判断文件是否存在
Golang 判断文件或文件夹是否存在的方法为使用 os.Stat() 函数返回的错误值进行判断。
- 如果返回的错误为 nil,说明文件或文件夹存在
- 如果返回的错误类型使用 os.IsNotExist() 判断为 true,说明文件或文件夹不存在
|
|
0.8 读取文件内容
- 读文件方式一:利用ioutil.ReadFile直接从文件读取到[]byte中
|
|
- 读文件方式二:先从文件读取到file中,在从file读取到buf, buf在追加到最终的[]byte
|
|
- 读文件方式三:先从文件读取到file, 在从file读取到Reader中,从Reader读取到buf, buf最终追加到[]byte
|
|
- 读文件方式四:读取到file中,再利用ioutil将file直接读取到[]byte中
|
|
四种方式读的速度排名是:前者为优 方式四 > 方式一 > 方式三 > 方式二
0.9 写文件内容
- 写文件方式一:使用 io.WriteString 写入文件
|
|
- 写文件方式二:使用 ioutil.WriteFile 写入文件
|
|
- 写文件方式三:使用 File(Write,WriteString) 写入文件
|
|
- 写文件方式四:使用 bufio.NewWriter 写入文件
|
|
JSON文件操作
0.10 编码JSON
-
编码json: 从其他类型编码成json字符串
-
encoding/json
- Marshal 返回interface{}类型 的json编码, 通常interface{}类型会使用map或者结构体
- MarshalIndent 类似于Marshal, 会使用缩进输出格式化json
-
使用map创建json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
package main import ( "encoding/json" "fmt" ) /** map创建json */ func main() { m:=make(map[string]interface{},3) m["name"] = "evan" m["age"] = 27 m["language"] = []string{"python","golang","javascript"} result,_:=json.Marshal(m) resultMarshalIndent,_:=json.MarshalIndent(m,""," ") fmt.Println(string(result)) fmt.Println(string(resultMarshalIndent)) } /** {"age":27,"language":["python","golang","javascript"],"name":"evan"} { "age": 27, "language": [ "python", "golang", "javascript" ], "name": "evan" } */
-
使用结构体创建json(常用)
- 当在定义struct 的时, 可以在后面添加标签来控制编码和解码的过程; 是否要编码或者解码某个字段, JSON中的名字字段名称是什么, 可以选择的控制字段有三种
- “-” :表示不要解析该字段
- “omitempty” : 当字段为空的时候不要解析该字段, 比如: false 0 nil 长度为0的array map slice string
- “FieldName” : 当解析JSON的时候使用这个名字
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
package main import ( "encoding/json" "fmt" ) type Person struct { Name string `json:"name"` Age int `json:"age"` Sex bool `json:"sex"` Birthday string `json:"birthday"` Company string `json:"company,omitempty"` Language []string `json:"language"` } func main() { person :=Person{"Evan",28,true,"1994","DCITS",[]string{ "python","golang", }} //result,err :=json.Marshal(person) result,err :=json.MarshalIndent(person,""," ") if err !=nil{ fmt.Println(err) return } fmt.Println(string(result)) } /** { "name": "Evan", "age": 28, "sex": true, "birthday": "1994", "company": "DCITS", "language": [ "python", "golang" ] } */
- 当在定义struct 的时, 可以在后面添加标签来控制编码和解码的过程; 是否要编码或者解码某个字段, JSON中的名字字段名称是什么, 可以选择的控制字段有三种
0.11 解析JSON
-
Unmarshal() 解析json,是Marshal()的反向操作
-
要将json数据解码写入一个接口类型值, 函数会将解码数据为如下对照关系写入接口
interface类型 json类型 Bool 布尔类型 Float64 数字类型 string 字符串类型 []interface{} 数组 map 对象 nil null - 如果json的值不满足或者不匹配给出的目标类型, 或者JSON数字写入目标类型时溢出, unmarsha()函数会跳过该字段, 尽可能满足其余的解码操作
-
struce 解码json(推荐使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
package main import ( "encoding/json" "fmt" ) type Person struct { Name string `json:"name"` Age int `json:"age"` Sex bool `json:"sex"` Birthday string `json:"birthday"` Company string `json:"company,omitempty"` Language []string `json:"language"` } func main() { jsonStr := ` { "name":"evan", "age":28, "sex":true, "birthday":"1994", "company":"DCITS", "language":["python","golang","javascript"] } ` var person Person err:=json.Unmarshal([]byte(jsonStr),&person) if err!=nil { fmt.Println(err) return } fmt.Println(person) } // {evan 28 true 1994 DCITS [python golang javascript]}
0.12 拓展 fastjson
- 速度是原生json操作速度的10倍
- 地址: https://github.com/valyala/fastjson
XML文件操作
-
XML是一门标记语言
-
XML对大小写敏感
-
Xml 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
<?xml version="1.0" encoding="utf-8" ?> <Wrapper> <Note> <To>George</To> <From>John</From> <Body> <Bodychild>bc1</Bodychild> <Bodychild>bc2</Bodychild> </Body> </Note> <Note> <To>George2</To> <From>John2</From> <Body> <Bodychild>bc1</Bodychild> <Bodychild>bc2</Bodychild> </Body> </Note> </Wrapper>
-
golang code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
package main import ( "encoding/xml" "fmt" "io/ioutil" ) type Wrapper struct { Note []Note } type Note struct{ To string From string Body Body } type Body struct { Bodychild []string } func main() { var res Wrapper content,err:=ioutil.ReadFile("test.xml") if err!=nil{ fmt.Println(err) return } err = xml.Unmarshal(content,&res) if err !=nil { fmt.Println(err) return } fmt.Println("解析后的xml文件为:") fmt.Println(res) }
-
按行读文件
-
方法一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
package main import ( "bufio" "fmt" "io" "os" ) const FilePath = "./test.txt" func readLineOfOne() { f, err := os.Open(FilePath) if err!=nil { fmt.Println(err) os.Exit(2) } defer f.Close() bufReader := bufio.NewReader(f) i := 0 for { i++ //fmt.Println(i) line,err:= bufReader.ReadBytes('\n') fmt.Println("->",string(line)) if err== io.EOF { fmt.Println("read file finished.") break }else if err!= nil { fmt.Println(err) os.Exit(2) } } } func main() { readLineOfOne() }
- bufReader.ReadBytes(’\n’)和 bufReader.ReadString(’\n’)在读到文件最后一行时,会同时返回内容line和io.EOF
bufio.Reader
- 方法一(一行一行读)
|
|
- 方法二
|
|
- bufReader.ReadBytes(’\n’)和 bufReader.ReadString(’\n’)在读到文件最后一行时,会同时返回内容line和io.EOF。而bufReader.Read()读取到末尾时,会先返回内容,然后再下一次迭代时才返回io.EOF
读写文件的四种方式
1 读文件
读取的文件放在file/test:也就是file包下的test这个文件,里面写多一点文件
-
读文件方式一:利用ioutil.ReadFile直接从文件读取到[]byte中
-
ioutil.ReadFile 将文件全部读到内存
|
|
-
读文件方式二:先从文件读取到file中,在从file读取到buf, buf在追加到最终的[]byte
-
os.Open 文件流的方式读取文件
|
|
- 读文件方式三:先从文件读取到file, 在从file读取到Reader中,从Reader读取到buf, buf最终追加到[]byte
|
|
- 读文件方式四:读取到file中,再利用ioutil将file直接读取到[]byte中
|
|
- 读取速度比较
经过我的测试,这四种方式读的速度排名是:前者为优 方式四 > 方式一 > 方式三 > 方式二
2 写文件
- 写文件方式一:使用 io.WriteString 写入文件
|
|
- 写文件方式二:使用 ioutil.WriteFile 写入文件
|
|
- 写文件方式三:使用 File(Write,WriteString) 写入文件
|
|
- 写文件方式四:使用 bufio.NewWriter 写入文件
|
|
- 检查文件是否存在:
|
|

