19-文件操作

文件的打开和关闭

  • 和C语言一样, Go语言中操作文件也是通过一个FILE结构体
type file struct {
    pfd     poll.FD
    name    string
    dirinfo *dirInfo 
}
type File struct {
    *file // os specific
}
  • Open函数
    • func Open(name string) (file *File, err error)
    • Open打开一个文件用于读取
  • Close函数
    • func (f *File) Close() error
    • Close关闭文件f
package main
import (
    "fmt"
    "os"
)

func main() {
    // 1.打开一个文件
    // 注意: 文件不存在不会创建, 会报错
    // 注意: 通过Open打开只能读取, 不能写入
    fp, err := os.Open("d:/lnj.txt")
    if err != nil{
        fmt.Println(err)
    }else{
        fmt.Println(fp)
    }

    // 2.关闭一个文件
    defer func() {
        err = fp.Close()
        if err != nil {
            fmt.Println(err)
        }
    }()
}

文件读取

  • Read函数(不带缓冲区去读)
    • func (f *File) Read(b []byte) (n int, err error)
    • Read方法从f中读取最多len(b)字节数据并写入b,
package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    // 1.打开一个文件
    // 注意: 文件不存在不会创建, 会报错
    // 注意: 通过Open打开只能读取, 不能写入
    fp, err := os.Open("d:/lnj.txt")
    if err != nil{
        fmt.Println(err)
    }else{
        fmt.Println(fp)
    }

    // 2.关闭一个文件
    defer func() {
        err = fp.Close()
        if err != nil {
            fmt.Println(err)
        }
    }()

    // 3.读取指定指定字节个数据
    // 注意点: \n也会被读取进来
    //buf := make([]byte, 50)
    //count, err := fp.Read(buf)
    //if err != nil {
    //  fmt.Println(err)
    //}else{
    //  fmt.Println(count)
    //  fmt.Println(string(buf))
    //}

    // 4.读取文件中所有内容, 直到文件末尾为止
    buf := make([]byte, 10)
    for{
        count, err := fp.Read(buf)
        // 注意: 这行代码要放到判断EOF之前, 否则会出现少读一行情况
        fmt.Print(string(buf[:count]))
        if err == io.EOF {
            break
        }
    }
}
  • ReadBytes和ReadString函数(带缓冲区去读)
    • func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
    • ReadBytes读取直到第一次遇到delim字节
    • func (b *Reader) ReadString(delim byte) (line string, err error)
    • ReadString读取直到第一次遇到delim字节
package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    // 1.打开一个文件
    // 注意: 文件不存在不会创建, 会报错
    // 注意: 通过Open打开只能读取, 不能写入
    fp, err := os.Open("d:/lnj.txt")
    if err != nil{
        fmt.Println(err)
    }else{
        fmt.Println(fp)
    }

    // 2.关闭一个文件
    defer func() {
        err = fp.Close()
        if err != nil {
            fmt.Println(err)
        }
    }()

    // 3.读取一行数据
    // 创建读取缓冲区, 默认大小4096
    //r :=bufio.NewReader(fp)
    //buf, err := r.ReadBytes('\n')
    //buf, err := r.ReadString('\n')
    //if err != nil{
    //  fmt.Println(err)
    //}else{
    //  fmt.Println(string(buf))
    //}

    // 4.读取文件中所有内容, 直到文件末尾为止
    r :=bufio.NewReader(fp)
    for{
        //buf, err := r.ReadBytes('\n')
        buf, err := r.ReadString('\n')
        fmt.Print(string(buf))
        if err == io.EOF{
            break
        }
    }
}
  • ReadFile函数
    • func ReadFile(filename string) ([]byte, error)
    • 从filename指定的文件中读取数据并返回文件的所有内容
    • 不适合大文件读取
package main

import (
    "fmt"
    "io/ioutil"
)

func main() {

    filePath := "d:/lnj.txt"
    buf, err := ioutil.ReadFile(filePath)
    if err !=nil {
        fmt.Println(err)
    }else{
        fmt.Println(string(buf))
    }
}

文件创建和写入

  • Create函数
    • func Create(name string) (file *File, err error)
    • Create采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件
    • 如果文件存在会覆盖原有文件
  • Write函数
    • func (f *File) Write(b []byte) (n int, err error)
    • 将指定字节数组写入到文件中
  • WriteString函数
    • func (f *File) WriteString(s string) (ret int, err error)
    • 将指定字符串写入到文件中
package main

import (
    "fmt"
    "os"
)

func main() {

    // 1.创建一个文件
    fp, err := os.Create("d:/lnj.txt")
    if err != nil{
        fmt.Println(err)
    }
    // 2.关闭打开的文件
    defer func() {
        err := fp.Close()
        if err != nil {
            fmt.Println(err)
        }
    }()
    // 2.往文件中写入数据
    // 注意: Windows换行是\r\n
    bytes := []byte{'l','n','j','\r','\n'}
    fp.Write(bytes)
    
    fp.WriteString("www.it666.com\r\n")
    fp.WriteString("www.itzb.com\r\n")
    // 注意: Go语言采用UTF-8编码, 一个中文占用3个字节
    fp.WriteString("李南江")
}
  • OpenFile函数
    • func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
    • 第一个参数: 打开的路径
    • 第二个参数: 打开的模式
    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  // 如果可能,打开时清空文件
    )
    
    • 第三个参数: 指定权限
      • 0没有任何权限
      • 1.执行权限(如果是可执行程序, 可以运行)
      • 2.写权限
      • 3.写权限和执行权限
      • 4.读权限
      • 5.读权限和执行权限
      • 6.读权限和写权限
      • 7.读权限和写权限以及执行权限
    const (
      // 单字符是被String方法用于格式化的属性缩写。
      ModeDir        FileMode = 1 << (32 - 1 - iota) // d: 目录
      ModeAppend                                     // a: 只能写入,且只能写入到末尾
      ModeExclusive                                  // l: 用于执行
      ModeTemporary                                  // T: 临时文件(非备份文件)
      ModeSymlink                                    // L: 符号链接(不是快捷方式文件)
      ModeDevice                                     // D: 设备
      ModeNamedPipe                                  // p: 命名管道(FIFO)
      ModeSocket                                     // S: Unix域socket
      ModeSetuid                                     // u: 表示文件具有其创建者用户id权限
      ModeSetgid                                     // g: 表示文件具有其创建者组id的权限
      ModeCharDevice                                 // c: 字符设备,需已设置ModeDevice
      ModeSticky                                     // t: 只有root/创建者能删除/移动文件
      // 覆盖所有类型位(用于通过&获取类型位),对普通文件,所有这些位都不应被设置
      ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
      ModePerm FileMode = 0777 // 覆盖所有Unix权限位(用于通过&获取类型位)
    )
    
  • 不带缓冲区写入
package main

import (
    "fmt"
    "os"
)

func main() {

    // 注意点: 第三个参数在Windows没有效果
    // -rw-rw-rw- (666)   所有用户都有文件读、写权限。
    //-rwxrwxrwx (777)  所有用户都有读、写、执行权限。
    // 1.打开文件
    //fp, err := os.OpenFile("d:/lnj.txt", os.O_CREATE|os.O_RDWR, 0666)
    fp, err := os.OpenFile("d:/lnj.txt", os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Println(err)
    }
    // 2.关闭打开的文件
    defer func() {
        err := fp.Close()
        if err != nil {
            fmt.Println(err)
        }
    }()

    // 注意点:
    // 如果O_RDWR模式打开, 被打开文件已经有内容, 会从最前面开始覆盖
    // 如果O_APPEND模式打开, 被打开文件已经有内容, 会从在最后追加
    // 3.往文件中写入数据
    bytes := []byte{'l','n','j','\r','\n'}
    fp.Write(bytes)
    fp.WriteString("www.it666.com\r\n")
}
  • 带缓冲区写入
package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {

    // 1.打开文件
    fp, err := os.OpenFile("d:/lnj.txt", os.O_CREATE|os.O_APPEND, 0666)
    if err != nil {
        fmt.Println(err)
    }
    // 2.关闭打开的文件
    defer func() {
        err := fp.Close()
        if err != nil {
            fmt.Println(err)
        }
    }()

    // 3.创建缓冲区
    w := bufio.NewWriter(fp)

    // 4.写入数据到缓冲区
    bytes := []byte{'l','n','j','\r','\n'}
    w.Write(bytes)
    w.WriteString("www.it666.com\r\n")

    // 5.将缓冲区中的数据刷新到文件
    w.Flush()
}
  • WriteFile函数
package main

import (
    "fmt"
    "io/ioutil"
)

func main() {

    // 1.写入数据到指定文件
    data := []byte{'l','n','j','\r','\n'}
    err := ioutil.WriteFile("d:/abc.txt", data, 0666)
    if err != nil {
        fmt.Println(err)
    }else{
        fmt.Println("写入成功")
    }
}

判断文件是否存在

  • Stat函数
    • func Stat(name string) (fi FileInfo, err error)
  • 返回值: FileInfo
type FileInfo interface {
    Name() string       // 文件的名字(不含扩展名)
    Size() int64        // 普通文件返回值表示其大小;其他文件的返回值含义各系统不同
    Mode() FileMode     // 文件的模式位
    ModTime() time.Time // 文件的修改时间
    IsDir() bool        // 等价于Mode().IsDir()
    Sys() interface{}   // 底层数据来源(可以返回nil)
}
  • 返回值: error
    • 返回值error等于nil,代表文件存在
    • 返回值error不等于nil, 可以进一步通过IsNotExist判断, 如果返回true代表文件不存在
    • 返回值error如果返回其它错误, 则不确定文件是否存在
package main

import (
    "fmt"
    "os"
)

func main() {

    info, err := os.Stat("d:/lnj.txt")
    if err == nil {
        fmt.Println("文件存在")
        fmt.Println(info.Name())
    }else if os.IsNotExist(err) {
        fmt.Println("文件不存在")
    }else{
        fmt.Println("不确定")
    }
}

练习

  • 将一个文本文件拷贝到另外一个文件中
    • 尝试用上面学习的其它方法实现下
package main

import (
    "fmt"
    "io/ioutil"
)

func main() {

    // 1.读取一个文件
    buf, err := ioutil.ReadFile("d:/lnj.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    // 2.写入读取的数据到另一个文件
    err =ioutil.WriteFile("d:/abc.txt", buf, 0666)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("拷贝完成")

}
  • 将一个图片/视频文件拷贝到另一个文件
package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {

    // 1.定义拷贝文件的路径
    scrPath := "D:/a.png"
    destPath := "E:/b.png"
    // 2.打开被拷贝文件
    fr, err := os.Open(scrPath)
    if err != nil {
        fmt.Println(err)
        return
    }
    // 3.关闭打开文件
    defer func() {
        err := fr.Close()
        if err != nil{
            fmt.Println(err)
        }
    }()
    // 4.创建读取缓冲区
    r := bufio.NewReader(fr)

    // 1.创建写入文件
    fw, err := os.Create(destPath)
    if err != nil {
        fmt.Println(err)
        return
    }
    // 2.关闭打开文件
    defer func() {
        err := fw.Close()
        if err != nil{
            fmt.Println(err)
        }
    }()
    // 3.创建写入缓冲区
    w := bufio.NewWriter(fw)
    // 4.利用系统copy函数完成拷贝
    count, err := io.Copy(w, r)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(count)
    fmt.Println("拷贝完成")
}
  • 自己查文档实现遍历文件夹
    • 例如: 给一个文件夹路径, 获取该文件夹下所有文件, 并将所有文件路径保存到切片中
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容