go语言文件读取以及IO操作

文章目录

  • 文件信息接口os.FileInfo
  • 文件的常规操作 (os包)
  • 文件的读取和写入 (io及os包)
  • ioutil包
  • bufio包

一、文件信息

os.FileInfo接口

接口属性

type FileInfo interface {
    Name() string       // 文件的名字
    Size() int64        // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同
    Mode() FileMode     // 文件的模式位 (例-rw-rw-r--)
    ModTime() time.Time // 文件的修改时间
    IsDir() bool        // 等价于Mode().IsDir()
    Sys() interface{}   // 底层数据来源(可以返回nil)
}

os.fileStat结构体实现了FileInfo接口的所有方法

type fileStat struct {
    name    string
    size    int64
    mode    FileMode
    modTime time.Time
    sys     syscall.Stat_t
}

示例

fileInfo, err := os.Stat("./aa.txt")
if err != nil{
    fmt.Println(err)
    return
}
fmt.Printf("%T: %v", fileInfo, fileInfo)  // *os.fileStat: &{aa.txt 23 ...}
fmt.Println(fileInfo.Name())              // aa.txt
fmt.Println(fileInfo.IsDir())             // false
fmt.Println(fileInfo.Size())              // 23
fmt.Println(fileInfo.Mode())              // -rw-rw-r--
fmt.Println(fileInfo.ModTime())           // 2019-02-15 14:44:39.745 +0800 CST

文件路径相关函数

路径相关的函数有两个包,pathpath/filepath,
两个包内有一些相同的函数,如IsAbs()Join()Dir()
filepath中的函数兼容各个操作系统,涉及到windows系统路径操作时,应该使用filepath

  • filepath.Rel(basepath, targpath string) (string, error)获取相对路径
  • filepath.Abs(path string) (string, error)获取绝对路径,如果path不是绝对路径,会加入当前工作目录以使之成为绝对路径。
  • path.Join(elem ...string) string路径拼接
  • path.IsAbs(path string) bool判断文件是否是绝对路径
  • path.Dir(path string) string获取目录

二、文件的常规操作

创建目录 如果存在则失败

  • os.Mkdir(name string, perm FileMode) error
    • 仅创建一层
    • 相当于linux命令mkdir
  • os.MkdirAll(path string, perm FileMode) error
    • 创建多层
    • 相当于linux命令mkdir -p

创建文件 如果存在会覆盖

  • os.Create(name string) (file *File, err error)
    • 底层调用 os.OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
    • 采用模式0666(任何人都可读写,不可执行)
    • 如果文件存在会清空它

打开文件

  • os.Open(name string) (file *File, err error)

    • 底层调用OpenFile(name, O_RDONLY, 0)
    • 以只读的方式打开文件
  • os.OpenFile(name string, flag int, perm FileMode) (file *File, err error)

    • perm可为06660777
    • flagos包中定义的常量:
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  // 如果可能,打开时清空文件
)

关闭文件

  • file.Close() error
    • *File指针的方法
    • 程序与文件之间的连接断开

删除文件或目录

  • os.Remove(name string) error
    • 只删除一层
    • 相当于linux命令rm
  • os.RemoveAll(path string) error
    • 删除path指定的文件,或目录及它包含的任何下级对象
    • 相当于linux命令rm -r

三、文件的读写操作

读取文件

  • os.Open(filename) --> *File
  • file.Read([]byte) --> n, err
    • 单次读取的字节数最大为[]byte的长度
    • n为实际读取到的字节数
    • 读取到末尾时errEOF(end of file)
  • file.Close()关闭文件

示例:

//step1:打开文件
fileName := ".text.txt"
file, err := os.Open(fileName)
if err != nil {
    fmt.Println("打开错误", err)
    return
}
//step2:读/写
//从file中读取最多len(bs)个字节,存入bs切边中,n是实际读取的数量
bs := make([]byte, 1024, 1024)
for {
    n, err := file.Read(bs)
    if n == 0 || err == io.EOF {
        fmt.Println("读取结束")
        break
    }
    fmt.Println(string(bs[:n]))
}
//step3:关闭文件
file.Close()

写入文件

写入文件与读取类似

  • os.Open(filename) --> *File
  • file.Write([]byte) --> n, err
    • []byte中的数据写入文件
  • file.WriteString(string) --> n, err
    • string写入文件
  • file.Close()

文件复制

  • io.Copy(dst Writer, src Reader) (written int64, err error)
    • dst和src为实现了接口io.Writer和io.Reader的实例

示例:

func copyFile(srcFile, destFile string) (int64, error) {
    file1, err := os.Open(srcFile)
    if err != nil {
        return 0, err
    }
    file2, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, os.ModePerm)
    if err != nil {
        return 0, err
    }
    defer file1.Close()
    defer file2.Close()
    return io.Copy(file2, file1)
}

四、ioutil包

  • ReadFile() --> ([]byte, error)
    • 读取所有数据,返回字节数组
  • WriteFile(filename string, data []byte, perm os.FileMode) --> error
    • 文件不存在则创建文件,存在则清空文件
    • os.FileMode可以直接用0666或者0777
  • ReadDir() --> ([]os.FileInfo, error)
    • 读取一个目录下的字内容,目录或文件,但是只有一层
    • 返回一个os.FileInfo切片

示例:

data, err := ioutil.ReadFile("aa.txt")
fmt.Println(string(data))
if err != nil {
    fmt.Println(err)
    return
}

err = ioutil.WriteFile("bb.txt", data, 0666)
if err != nil {
    fmt.Println(err)
    return
}

fileInfos, err := ioutil.ReadDir(".")
if err != nil {
    fmt.Println(err)
    return
}
for i := range fileInfos {
    fmt.Println(i, fileInfos[i].IsDir(), fileInfos[i].Name())
}

五、bufio包

  • bufio包实现了有缓冲的I/O
  • bufio封装了一个Reader݊及Writer结构体,分别实现了io.Readerio.Writer接口
  • 通过对对io模块的封装,提供了带有缓冲的io操作,减小了大块数据读写的io开销

io.Reader和io.Writer

type Reader interface {
    Read(p []byte) (n int, err error)
}

type Writer interface {
    Write(p []byte) (n int, err error)
}

os.Open(name string) (*File, error)返回的文件指针就实现了io.Reader

bufio.Reader结构体

  • NewReader(rd io.Reader) *Reader
    • NewReader创建一个具有默认大小缓冲、从r读取的*Reader
  • Reader.Read(p []byte) (n int, err error)
    • Read读取数据写入p。本方法返回写入p的字节数
    • 返回值n可能小于len(p),读取到达结尾时,返回值n将为0err将为io.EOF
    • 类似File.Read()方法

示例:

s := strings.NewReader("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
br := bufio.NewReader(s)
b := make([]byte, 20)

n, err := br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)  // ABCDEFGHIJKLMNOPQRST 20 <nil>

n, err = br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)  // UVWXYZ1234567890 16 <nil>

n, err = br.Read(b)
fmt.Printf("%-20s %-2v %v\n", b[:n], n, err)  // 0 EOF
  • Reader.ReadBytes(delim byte) (line []byte, err error)
    • delimdelimiter的缩写意为定位符
    • ReadBytes读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的切片

示例:

s := strings.NewReader("ABCDEFG\n123456\n")
br := bufio.NewReader(s)

for {
    sli, err := br.ReadBytes('\n')
    if err err == io.EOF {
        break
    }
    fmt.Println(sli)
}
// [65 66 67 68 69 70 71 10]
// [49 50 51 52 53 54 10]
  • Reader.ReadString(delim byte) (line string, err error)
    • 返回的是字符串类型

示例:

s := strings.NewReader("ABCDEFG\n123456\n")
br := bufio.NewReader(s)
for {
    s, err := br.ReadString('\n')
    if err err == io.EOF {
        break
    }
    fmt.Print(s)
}
// ABCDEFG
// 123456

bufio.Writer结构体

  • NewWriter(w io.Writer) *Writer
    • NewWriter创建一个具有默认大小缓冲、写入w*Writer
  • Writer.Write(p []byte) (nn int, err error)
    • Writep的内容写入缓冲。返回写入的字节数。如果返回值nn < len(p),还会返回一个错误说明原因
    • 类似File.Write()方法
  • Writer.WriteString(s string) (int, error)
    • 写入一个字符串,返回写入的字节数
  • Writer.Flush() error
    • Flush方法将缓冲中的数据输出

示例:

file1, _ := os.Open("aa.txt")
defer file1.Close()
reader := bufio.NewReader(file1)
file2, _ := os.Create("cc.txt")
defer file2.Close()
writer := bufio.NewWriter(file2)

for {
    bs, err := reader.ReadBytes('\n')
    if err == io.EOF {
        fmt.Println("读取完毕")
        break
    }
    writer.Write(bs)
    writer.Flush()
}

bufio.Scanner结构体

  • NewScanner(r io.Reader) *Scanner
    • 创建并返回一个从r读取数据的Scanner,默认的分割函数是ScanLines
    • 通过Scanner.Split(split SplitFunc)方法,可以为Scanner指定splitFunc
    • Scanner可以通过plitFunc将r中的数据拆分为多个token,然后通过Scanner.Scan()依次读取
  • bufio中提供的默认splitFunc
    • ScanBytes,按照byte进程拆分
    • ScanRunes,按照行("\n")进程拆分
    • ScanWords,按照utf-8字符进行拆分
    • ScanLines,按照单词(" ")进程拆分
  • 常用方法
    • Split(split SplitFunc)
    • Scan() bool
    • Text() string
    • Bytes() []byte

示例:

scanner := bufio.NewScanner(os.Stdin)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
    if scanner.Text() == "q" {
        break
    }
    fmt.Println(scanner.Text()) // Println will add back the final '\n'
}
if err := scanner.Err(); err != nil {
    fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容