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代表同一地址的最短路径。

它会不断的依次应用如下的规则,直到不能再进行任何处理:

  1. 将连续的多个斜杠替换为单个斜杠
  2. 剔除每一个.路径名元素(代表当前目录)
  3. 剔除每一个路径内的..路径名元素(代表父目录)和它前面的非..路径名元素
  4. 剔除开始一个根路径的..路径名元素,即将路径开始处的"/.."替换为"/"

只有路径代表根地址"/"时才会以斜杠结尾。如果处理的结果是空字符串,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)
*PathErrornameflag
  1. O_RDONLY:以只读的方式打开
  2. O_WRONLY:以只写的方式打开
  3. O_RDWR:以读写的方式打开
  4. O_APPEND:以追加方式打开文件,写入的数据将追加到文件尾
  5. O_CREATE:当文件不存在时创建文件
  6. O_EXCL:与O_CREATE一起使用,当文件存在时Open失败
  7. O_SYNC:以同步方式打开文件。每次write系统调用后等等待实际的物理I/O完成后才返回,默认(不使用该标记)是使用缓冲的,也就是说每次的写操作是写到系统内核缓冲区中,等系统缓冲区满后才写到实际存储设备中。
  8. O_TRUNC:如果文件已存在,打开是会清空文件内容。必须于O_WRONLY或O_RDWR配合使用。截断文件,需要有写的权限。
FileMode

写文件

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)
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 学习笔记(07)—— 错误及异常处理
下一节:Golang 学习笔记(09)—— json和xml解析