Go文件操作
- 文件是数据源(保存数据的地方)的一种
- 输入流与输出流
- 文件在程序中是以流的形式来操作的
- 流:数据在数据源(文件)和程序(内存)之间经历的路径
- 输入流:数据从数据源(文件)到程序(内存)的路径
- 输出流:数据从程序(内存)到数据源(文件)的路径
- os.File封装所有文件操作,File是一个结构体
常用文件操作和方法
打开与关闭文件
func Open(name string)(file *File,err error)
- Open打开一个文件用于读取,如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError
func (f *File)Close()error
- Close关闭文件,使文件不能用于读写,其返回可能出现的错误
package main
import (
"fmt"
"os"
)
func main(){
//打开文件
//file的叫法
//file对象
//file指针
//file文件句柄
file,err := os.Open("d:/test.txt")
if err != nil {
fmt.Println("open file err="err)
}
//输出文件,查看文件是声明,文件时一个指针*file
fmt.Printf("file=%v",file)
//关闭文件
err = file.Close()
if err != nil {
fmt.Println("close file err=",err)
}
}
//读取文件的内容并显示在终端(带缓冲方式)
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main(){
//打开文件
//file的叫法
//file对象
//file指针
//file文件句柄
file,err := os.Open("d:/test.txt")
if err != nil {
fmt.Println("open file err=",err)
}
//当函数退出时,要及时关闭file,否则会内存泄漏
defer file.Close()
//创建一个*Reader,是带缓冲的
/*
const(
defaultBufSize = 4096 //默认的缓冲区为4096
)
*/
reader := bufio.NewReader(file)
//NewReader创建一个具有默认大小缓冲、从r读取的*Reader
//循环读取文件的内容
for {
str,err := reader.ReadString('\n')//读到一个换行就结束
if err == io.EOF {//io.EOF表示文件的末尾
break
}
fmt.Print(str)
}
fmt.Println("文件读取结束...")
}
package main
import (
"fmt"
"io/ioutil"
)
//读取文件的内容并显示在终端(使用ioutil一次将整个文件读入内存中)
//适用于文件不大的情况
func main(){
//使用ioutil.Readfile一次性将文件读取到位
file := "d:/test.txt"
content,err := ioutil.ReadFile(file)
if err != nil {
fmt.Printf("read file err = %v",err)
}
//把读取到的内容显示到终端
fmt.Printf("%v",content)//[]type输出数字
fmt.Printf("%v",string(content))
//没有显示的Open文件,因此不需要显示的Close文件
//文件的Open和Close被封装到ReadFile函数内部
}
创建文件并写入内容
- 文件打开模式 (可用**|**组合)
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//如果可能,打开时清空文件
)
- os.OpenFile时是一个更一般性的文件打开函数,会使用指定的选项、指定的模式打开指定名称的文件。如果操作成功,返回文件对象可用于I/O。如果出错,错误底层类型是*PathError
func OpenFile(name string,flag int,perm FileMode)(file *File,err error)
//第二个参数:文件打开模式
//第三个参数:权限控制(linux)
//创建一个新文件,写入内容5局“hello”
package main
import (
"fmt"
"bufio"
"os"
)
func main(){
//创建一个文件,写入内容
//打开文件
filePath := "d:/abc.txt"
file,err := os.OpenFile(filePath,os.O_WRONLY | os.O_CREATE,0666)
if err != nil {
fmt.Printf("open file err = ",err)
return
}
//及时关闭file句柄
defer file.Close()
//写入内容
str := "hello"
//写入时,使用带缓冲的*Writer
writer := bufio.NewWriter(file)
for i := 0; i < 5;i++ {
writer.WriteString(str)
}
//因为writer是带缓存的,因此在调用WriterString方法时
//内容是先写入到缓存区的,所以需要调用Flush方法
//将缓存数据写入到文件中,否则文件会没有数据
writer.Flush()
}
判断文件是否存在
- Golang使用os.Stat()函数返回的错误值进行判断
- nil:说明文件或文件夹存在
- 若返回的错误类型使用os.IsNotExist()判断为true,说明文件或文件夹不存在
- 返回的错误为其他类型,则不确定是否存在
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)
//copy函数是由io包提供
package main
import (
"fmt"
"os"
"io"
"bufio"
)
func CopyFile(dstFileName string,srcFtleName string)(written int64,err error){
srcFile,err := os.Open(srcFileName)
if err != nil {
fmt.Printf("open file err=%v\n",err)
}
defer srcFile.Close()
//通过srcFile获取Reader
reader := bufio.NewReader(srcFile)
//打开dstFileName
dstFile,err := os.OpenFile(desFileName,os.O_WRONLY|os.O_CREATE,0666)
if err != nil {
fmt.Printf("open file err = %v\n",err)
return
}
//通过dstFile 获取writer
write := bufio.NewWriter(dstFile)
defer dstFile.Close()
return io.Copy(writer,reader)
}
func main(){
srcFile := "d:/flower.jpg"
dstFile := "e:/abc.jpg"
_,err := CopyFile(dstFile,srcFile)
if err != nil {
fmt.Printf("拷贝完成\n")
} else {
fmt.Printf("拷贝错误 err=%v\n",err)
}
}
命令行参数
-
os.Args是一个string的切片。用于存储所有命令行参数
-
获取命令行参数
package main
import (
"fmt"
"os"
)
func main(){
fmt.Println("命令行参数有",len(os.Args))
//遍历os.Args切片,就可以得到所有命令行输入参数值
for i,v := range os.Args {
fmt.Printf("Args[%v]=%v\n",i,v)
}
}
- flag包用于解析命令行参数
- 参数顺序可以随意
package main
import (
"fmt"
"flag"
)
func main() {
var user string
var pwd string
var host string
var port int
//&user就是接受用户命令行中输入的-u后面的参数值
//“u”就是-u指定参数
//“”默认值
//“用户名默认为空”说明
flag.StringVar(&user,"u","","用户名默认为空")
flag.StringVar(&pwd,"pwd","","密码默认为空")
flag.StringVar(&host,"h","localhost","主机名,默认为localhost")
flag.IntVar(&port,"port","3306","端口号默认为3306")
//转换,必须调用该方法
fmt.Printf("user=%v pwd=%v host=%v port=%v",user,pwd,host,port)
}
json基本介绍
-
JSON是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成
-
JSON易于机器解析和生成,并能够有效提升网络传输效率,通常程序在网络传输时会先将数据(结构体、map等)序列化成JSON字符串,到接收方得到JSON字符串时,再反序列化恢复成原来的数据类型(结构体、map等)
-
在JS语言中,一切都是对象,任何数据类型都可以通过JSON表示
-
JSON键值对是用来保存数据的一种方式
-
{"firstname":"Json"} {"name":"tom","age":18,"address":["北京","上海"]} [{"name":"tom","age":18,"address":["北京","上海"]}, {"name":"mary","age":28,"address":["广州","深圳"]}]
-
JSON数据在线解析
- https://www.json.cn/可以验证JSON格式是否正确
JSON序列化
package main
import (
"encoding/json"
"fmt"
)
//定义一个结构体
type Monster struct {
Name string `json:"monster_name"`//反射机制
Age int `json:"monster_age"`
Birthday string
Sal float64
Skill string
}
func testStruct(){
monster := Monster{
Name : "牛魔王",
Age : 500,
Birthday : "2011-11-11",
Sal : 8000.0,
Skill : "牛魔拳",
}
//将monster序列化
data,err := json.Marshal(&monster)
if err != nil {
fmt.Printf("序号错误 err=%v\n",err)
}
//输出序列后结果
fmt.Printf("monster序列后=%v\n",string(data))
}
//将map序列化
func testMap(){
//定义一个map
var a map[string]interface{}
//使用map需要make
a = make(map[string]interface{})
a["name"] = "红孩儿"
a["age"] = 30
a["address"] = "洪崖洞"
//将a这个map进行序列化
//将monster序列化
data,err := json.Marshal(a)
if err != nil {
fmt.Printf("序列化错误,err=%v\n",err)
}
//输出序列化结果
fmt.Printf("a map 序列化后=%v\n",string(data))
}
//将切片序列化
func testslice(){
var slice []map[string]interface{}
var m1 map[string]interface{}
//使用map前,需要先make
m1 = make(map[string]interface{})
m1["name"] = "jack"
m1["age"] = "7"
m1["address"] = "北京"
slice = append(slice,m1)
var m2 map[string]interface{}
//使用map前需要先make
m2 = make(map[string]interface{})
m2["name"] = "tom"
m2["age"] = "20"
m2["address"] = [2]string{"墨西哥","夏威夷"}
slice = append(slice,m2)
//将切片进行序列化操作
data,err := json.Marshal(slice)
if err != nil {
fmt.Printf("序列化失败错误,err=%v\n",err)
}
//输出序列化后结果
fmt.Printf("slice 序列化后=%v\n",string(data))
}
func main(){
testStruct()
testMap()
testslice()
//对于结构体的序列化,如果希望序列化后key的名字重新制定
//可以给struct一个tag标签
}
JSON的反序列化
package main
import (
"fmt"
"encoding/json"
)
//定义一个结构体
type Monster struct{
Name string
Age int
Birthday string
Sal float64
Skill string
}
//将JSON字符串反序列化成struct
func unmarshalStruct(){
//说明str在项目开发中,是通过网络传输获取到或者是读取文件获取到
str := "{\"Name\":\"牛魔王\",\"Age\":500,\"Birthday\":\"2011-11-11\",\"Sal\":8000,\"Skill\":\"牛魔拳\"}"
//定义一个Monster实例
var monster Monster
err := json.Unmarshal([]byte(str),&monster)
if err != nil {
fmt.Printf("unmarshall err=%v\n",err)
}
fmt.Printf("反序列化后monster=%v monster.Name=%v\n",monster,monster.Name)
}
//将JSON字符串反序列化成map
func unmarshalMap(){
str := "{\"address\":\"洪崖洞\",\"Age\":30,\"name\":\"红孩儿\"}"
//定义一个map
var a map[string]interface{}
//反序列化不需要make,因为make操作被封装到Unmarshal函数
err := json.Unmarshal([]byte(str),&a)
if err != nil {
fmt.Printf("ummarshal err=%v\n",err)
}
fmt.Printf("反序列化后 a=%v\n",a)
}
//将JSON字符串反序列化成切片
func unmarshalSlice(){
str := "[{\"address\":\"北京\',\"age\":\"7\",\"name\":\"jack\"},"+
"{\"address\":[\"墨西哥\",\"夏威夷\"],\"age\":\"20\",\"name"\:\"tom\"}]"
//定义一个slice
var slice []map[string]interface{}
err := json.Unmarshal([]byte(str),&slice)
if err != nil {
fmt.Printf("unmarshal err = %v\n",err)
}
fmt.Printf("反序列化后 slice=%v\n",slice)
}
func main(){
unmarshalMap()
unmarshalSlice()
unmarshalStruct()
//在反序列化一个json字符串时,要确保反序列化后的数据类型和原来序列化前的数据类型一致
//如果json字符串是从程序中获取的,则不需要对"转义处理
}