文件分类:
文本文件(记事本打开能正常显示的文件)
二进制文件(图片,可执行程序,压缩包)
目录基本操作:
Windows目录不区分大小写,Linus目录区分
有关io操作的标准库
标准库 | 功能 |
---|---|
io | 为IO原语提供基本的接口 |
io/ioutil | 封装一些实用的I/O函数 |
fmt | 实现格式化I/O |
bufio | 实现带缓冲I/O |
读取目录:
io/ioutil .ReadDir() 返回一个有序列表,内容为指定的目录信息
func ReadDir(dirname string) ([]os.FileInfo,error)
type FileInfo interface{
Name() string //文件名称
Size() int64 //文件长度
Mode() FileMode //文件打开模式
ModTime() time.Time //文件的修改时间
IsDir() bool //是否是文件夹
Sys() interface //基础数据源
}
func main(){
ListDir("C:\\Users")
}
func ListDir(dirPath string) error {
dir,err := ioutil.ReadDir(dirPath)
if err != nil{
return err
}
for _,fi := dir{
if fi.IsDir{
fmt.Println("目录:",fi.Name())
}elsr{
fmt.Println("文件: ",fi.Name())
}
}
return nil
}
获取目录下的所有文件名(包含子文件的所有文件)
即递归遍历一个文件夹的所有文件夹:path/filepath Walk()方法
func Walk(root string,walkFn WalkFunc) error
Walk函数会遍历root指定目录下的文件树,对每一个文件树中的目录和文件都会调用walkFn,包括root本身,所有访问文件,目录时遇到的错误都会传递给walkFn过滤。遍历出来的文件按词法顺序遍历,输出更漂亮,但是处理大目录效率会降低。
Walk函数不会遍历文件树的中的符号链接(快捷方式)文件包含的路径。
func WalkDir(path string){
err := filepath.Walk(path,func(path string,f os.FileInfo,err error) error {
if f == nil{
return nil
}
if f.IsDir() {
return nil
}
println(path)
return nil
})
if err != nil{
fmt.Printf("filepath.Walk() returned %v\n",err)
}
}
func main(){
WalkDir("C:\\Windows\\Temp")
}
创建目录:
func Mkdir(name string,path FileMode) error
使用指定的权限和名称创建一个目录,如果出错,返回*PathError底层类型(语言自带的类型)的错误
例如:没有足够的权限创建一个文件夹时会报出"Access is denied"
局限性:Mkdir一次只能创建一级目录,且目录存在时会报错,
创建多级目录可以用MkdirAll 且目录存在时不会报错直接返回nil
func MkdirAll(path string,perm FileMode) error
删除目录:
func Remove(name string ) error
只能删除空文件夹,非空会报错
删除非空文件夹,可以使用os.RemoveAll(name string) error 方法
文件基本操作:
权限 | 权限数值 | 具体作用 |
---|---|---|
r | 4 | 当前用户可以读取文件内容,目录 |
w | 2 | 当前用户可以新增,修改文件内容;删除,移动目录或目录内文件 |
x | 1 | 当前用户可以执行文件;进入目录 |
Linux下权限的粒度有拥有者,所属组,其他组
每个文件可以针对三种粒度,设置不同的rwx。
例如:777权限就代表给这个文件的拥有者,所属组,其他用户赋予读写执行权限
通常情况下,一个文件只能归属于一个用户和组,如果其他用户想拥有这个文件的权限,可以将该用户加入具备权限的群组。
文件打开:
os.OpenFile(name string,flag int,perm FileMode) (file *File,err error)
这是一个更底层的文件打开函数,大多数调用者应该Open或Create代替本函数。
位掩码参数flag指定文件的访问模式
const (
O_RDONLY int = syscall.O_RDONLY //只读模式打开文件
O_WDONLY int = syscall.O_WRONLY //只写模式打开文件
O_RDWR int = syscall.O_RDWR //读写模式打开文件
O_APPEND int = syscall.O_APPEND //写操作时将数据附加到文件尾部
O_CREATE int = syscall.O_CREATE //如果不存在创建一个新文件
O_EXCL int = syscall.O_EXCL //和O_CREATE配合使用,文件必须不存在
O_SYNC int = syscall.O_SYNC //打开文件用于同步I/O
O_TRUNC int = syscall.O_TRUNC //如果可能,打开时清空文件
)
O_RDONLY(只读打开文件),O_WRONLY(只写打开文件),O_RDWR(读写打开文件)这三个只能指定一个,其他与|操作符来指定。
该函数内部会给flags加上syscall.O_CLOEXEC,在fork子进程时会关闭OpenFile打开的文件,即子进程不会重用该文件描述符。
位掩码参数perm指定了文件的模式和权限位,类型是os.FileMode,比如0777覆盖所有的Unix权限位。
os.Open()以只读(O_RDONLY)的方式打开文件
os.Create()以读取(O_RDWR|O_CREATE(没有则创建文件)|O_TRUNC(打开时清空文件)的方式打开文件,且文件权限为0666,任何人可读写,不可执行,如果文件已存在就会清空。
func Open(name string) (*File,error){
return OpenFile(name,O_RDONLY,0)
}
func Create(name string) (*File,error){
return OpenFile(name,O_RDWR|O_CREATE|O_TRUNC,0666)
}
文件读取:
func (f *File) Read(b []byte) (n int,err error)
从文件读取最多len(b)字节数据写入byte数组b,但是当遇到特别大的文件时,并且只需读取文件的最后部分的内容时就不能满足。
func (f *File) ReadAt (b []byte,off int64) (n int,err error)
从指定位置开始读取len(b)字节数据写入byte数组b n代表返回读取的字节数
两者区别在于,前者从文件当前偏移量开始读取,且会改变文件当前的偏移量;后者从off指定的位置开始读取,其不会改变文件当前的偏移量。
func ReadFile(path string){
file,err := os.Open(path)
if err != nil{
fmt.Println(err)
}
buf := make([]byte,1024)
for {
len,_ := file.Read(buf)
if len == 0{
break
}
fmt.Println(string(buf))
}
file.Close()
}
func ReadFile2(path string){
file,err := os.Open(path)
if err != nil{
fmt.Println(err)
}
buf := make([]byte,1024)
_,_ := file.ReadAt(buf,9)
fmt.Println(string(buf))
file.Close()
}
func main(){
ReadFile("C:\\Windows\\Temp\\1.txt")
ReadFile2("C:\\Windows\\Temp\\1.txt")
}
文件写入:
func (f *File) Write(b []byte) (n int, err error)
func (f *File) WriteAt(b []byte,off int64) (n int ,err error)
两者对文件进行写入时会将原文件覆盖,并从文件开始(指定)位置开始写入内容。
func main(){
file,err := os.Create("C:\\Windows\\Temp\\1.txt")
if err != nil{
fmt.Println(err)
}
data := "我是数据\n"
for i:=0;i<3;i++{
file.Write([]byte(data))
}
flie.Close
}
删除文件:
os.Remove()删除文件,
os.RemoveAll()删除指定path下的所有文件。
func main(){
ii err:= os.Remove("C:\\Windows\\Temp\\1.txt");err != nil{
fmt.Println(err)
}else{
fmt.Println("删除成功")
}
if err = os.RemoveAll("C:\\Windows\\Temp\\test");err !=nil{
fmt.Println(err)
}else{
fmt.Println("删除成功")
}
}
处理JSON文件:
JSON是一种轻量级的数据交换格式,最初是JavaScript的一部分,由于其良好的可读性和便于快速编写的特性,独立于语言。 适用于网络编程
编码JSON:
func Marshal(v interface{}) ([]byte,error) v通常为map 或结构体
func MarshalIndent(v interface{}, prefix, indent string) ([]byte,error)
类似Marshal 会使用缩进将输出格式化,适用于Map。
func main(){
m := make(map[string]interface{},6)
m["name"] = "Tom"
m["age"] = 24
m["sex"] = true
m["birthday"] = "1995-01-01"
m["company"] = "天一"
m["language"] = []string{"Go","PHP","Python"}
result,_ := json.Marshall(m)
resultFormat,_ := json.MarshallIndent(m,""," ")
fmt.Println("result = ",string(result))
fmt.Println("resultFormat = ",string(resultFormat))
}
解码JSON:
func Unmarshal(data []byte,v interface{}) error
一般用结构体解码,因为Map解码JSON需要类型断言,struct解析JSON时,JSON库会自动对结构体的类型进行解析,无需类型判断。
在定义struct字段时,可以在字段后面添加标签控制编码/解码过程。可选择的控制字段有
标签 | 作用 |
---|---|
- | 不要解析这个字段 |
omitempty | 当字段为空时,不要解析 比如false,0,nil,长度为0的array,map,slice,string |
FieldName | 表示将属性的key值解析为FieldName |
type Person struct{
Name string `json:"name"`
Age int `json:"int"`
Sex bool `json:"sex"`
Birthday string `json:"birthday"`
Company string `json:"company"`
Language []string `json:"language"`
}
func main(){
jsonStr := `
{
"name": "Tom",
"age": 34,
"sex": true,
"birthday": "1990-09-23",
"company": "TIME",
"language":["GO","PHP"]
}
`
var person Person
res,err := json.Unmarshall([]byte(jsonStr),&person)
if err != nil{
fmt.Println(err)
}
fmt.Println("person = ",person)
}
如果一个JSON值不匹配给出的目标类型,或者一个JSON数字写入目标类型时溢出,会跳过该字段并尽量完成其余解码操作。
提升:github开源了一个比标准库解析速度快10倍的fastjson库,可以尝试以下