• [go学习笔记.第十二章.文件操作] 1.文件的基本介绍以及基本操作


     一.文件的基本介绍

    文件,对我们并不陌生,文件是数据源(保存数据的地方)的一种,比如大家经常使用的word文档, txt 文件,excel文件 … 都是文件.文件最主要的作用就是保存数据,它既可以保存一张图片也可以保存视频,声音...

    输入流和输出流

    文件在程序中是以流的形式来操作的

    :数据在数据源(文件)和程序(内存)之间经历的路径

    输入流: 数据从数据源(文件)到程序 ( 内存)的路径

    输出流: 数据从程序(内存)到数据源(文件)的路径

    os.File封装了所有与文件相关的操作,File是一个结构体

     二.文件的基本操作

    1.打开文件和关闭文件

    1. package main
    2. import (
    3. "fmt"
    4. "os"
    5. )
    6. func main() {
    7. //打开文件(文件是一个指针类型)
    8. //概念: file叫法: 1. file对象 2.file指针 3.file 文件句柄
    9. file, err := os.Open("f:/www/test.txt")
    10. if err != nil {
    11. fmt.Printf("open file err = %v\n", err) //open filt err = %v open f:www/test.txt: The system cannot find the path specified.
    12. }
    13. //输出文件,可以看出:文件就是一个指针
    14. fmt.Printf("file=%v\n", file) // 打开文件成功: file=&{0xc000088280}, 打开文件失败:file=<nil>
    15. //关闭文件
    16. err = file.Close()
    17. if err != nil {
    18. fmt.Println("close file err= %v", err)//close file err= %v invalid argument
    19. }
    20. }

    2.读取文件操作

    (1).读取文件的内容并显示在终端(带缓冲区的方法),使用os.Open,file.Close,bufio.NewReader,reader.ReadString函数和方法

    1. package main
    2. import (
    3. "fmt"
    4. "os"
    5. "bufio"
    6. "io"
    7. )
    8. func main() {
    9. //打开文件(文件是一个指针类型)
    10. //概念: file叫法: 1. file对象 2.file指针 3.file 文件句柄
    11. file, err := os.Open("f:/www/test.txt")
    12. if err != nil {
    13. fmt.Printf("open file err = %v\n", err) //open filt err = %v open f:www/test.txt: The system cannot find the path specified.
    14. }
    15. //当函数退出时,关闭file,避免内存泄漏
    16. defer file.Close()
    17. //创建一个 *Reader,是带缓冲的
    18. /**
    19. * const (
    20. * defaultBufSize = 4096 // 默认的缓冲区为4096
    21. * )
    22. */
    23. //NewReader创建一个具有默认大小缓冲、从r读取的*Reader
    24. reader := bufio.NewReader(file)
    25. //循环读取文件中的内容
    26. for {
    27. str, err := reader.ReadString('\n') //读到一个换行符结束
    28. if err == io.EOF { //io.EOE 表示文件的末尾
    29. break
    30. }
    31. //输出内容
    32. fmt.Print(str)
    33. }
    34. fmt.Println("文件读取结束")
    35. }

     (2).读取文件的内容并显示在终端(使用ioutil一次性地将整个文件读入到内存中),这种方式适用于文件不大的情况,使用的相关方法和函数:ioutil.ReadFile

    1. package main
    2. import (
    3. "fmt"
    4. "io/ioutil"
    5. )
    6. func main() {
    7. //使用io/ioutil.ReadFile一次性将文件读取到位
    8. file := "f:/www/test.txt"
    9. //ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报告的错误
    10. content, err := ioutil.ReadFile(file)
    11. if err != nil {
    12. fmt.Printf("read file err = %v", err)
    13. }
    14. //把读取到文件内容显示到终端
    15. // fmt.Printf("%v\n", content) //[]byte
    16. fmt.Printf("%v\n", string(content)) //要显示正确的内容,需要把byte切片转换成string
    17. //没有显示的Open文件,因此也不需要显示的Close文件,因为文件的Open,Close被封装到ReadFile函数内部
    18. }

     3.写文件操作

    os.OpenFile函数介绍

    第二个参数 flag:文件打开模式(可以组合)参数如下:

     第三个参数 perm:权限控制参数如下:

    r:读 ===> 4

    w:写 ===> 2

    x: 执行 ===> 1

    方式一

    (1).创建一个新文件,写入内容: 5句 "hello world"

    1. package main
    2. import (
    3. "fmt"
    4. "bufio"
    5. "os"
    6. )
    7. func main() {
    8. //创建一个新文件,写入内容:5聚 hello world
    9. //打开一个文件 "f:/www/test2.txt"
    10. filePath := "f:/www/test2.txt"
    11. file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE, 0666)//O_WRONLY 只写模式打开文件 ,O_CREATE 如果不存在将创建一个新文件,写的方式打开,新增
    12. if err != nil {
    13. fmt.Printf("open file err =%v\n", err)
    14. }
    15. //及时关闭
    16. defer file.Close()
    17. //准备写入5句内容
    18. content := "hello world\r\n"
    19. //NewWriter创建一个具有默认大小缓冲、写入w的*Writer
    20. writer := bufio.NewWriter(file)
    21. for i := 0; i < 5; i++ {
    22. //WriteString写入一个字符串。返回写入的字节数。如果返回值nn < len(s),还会返回一个错误说明原因
    23. writer.WriteString(content)
    24. }
    25. //因为Writer是带缓冲的,因此在调用WriterString方法时,其实内容是先写入到缓冲的
    26. //所以需要调用Flush方法,将缓冲中的数据真正写入到文件中,否则文件中会丢失数据
    27. //Flush方法将缓冲中的数据写入下层的io.Writer接口
    28. writer.Flush()
    29. }

    (2).打开一个存在的文件,将原来的内容覆盖成新的内容,10句 "hello,你好" 

    1. package main
    2. import (
    3. "fmt"
    4. "bufio"
    5. "os"
    6. )
    7. func main() {
    8. //打开一个存在的文件,将原来的内容覆盖成新的内容10句:你好,world
    9. //打开一个存在文件 "f:/www/test2.txt"
    10. filePath := "f:/www/test2.txt"
    11. file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_TRUNC, 0666) //O_WRONLY 只写模式打开文件,O_TRUNC 打开时清空文件
    12. if err != nil {
    13. fmt.Printf("open file err =%v\n", err)
    14. }
    15. //及时关闭
    16. defer file.Close()
    17. //准备写入5句内容
    18. content := "你好,world\r\n"
    19. writer := bufio.NewWriter(file)
    20. for i := 0; i < 5; i++ {
    21. //WriteString写入一个字符串。返回写入的字节数。如果返回值nn < len(s),还会返回一个错误说明原因
    22. writer.WriteString(content)
    23. }
    24. //因为Writer是带缓冲的,因此在调用WriterString方法时,其实内容是先写入到缓冲的
    25. //所以需要调用Flush方法,将缓冲中的数据真正写入到文件中,否则文件中会丢失数据
    26. //Flush方法将缓冲中的数据写入下层的io.Writer接口
    27. writer.Flush()
    28. }

    (3).打开一个文件,在原来的内容追加内容, 5句 "你好,world"

    1. package main
    2. import (
    3. "fmt"
    4. "bufio"
    5. "os"
    6. )
    7. func main() {
    8. //打开一个存在的文件,将原来的内容覆盖成新的内容10句:你好,world
    9. //打开一个存在文件 "f:/www/test2.txt"
    10. filePath := "f:/www/test2.txt"
    11. file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_APPENDC, 0666)//O_WRONLY
    12. 只写模式打开文件,O_APPENDC 写操作时将数据附加到文件尾部
    13. if err != nil {
    14. fmt.Printf("open file err =%v\n", err)
    15. }
    16. //及时关闭
    17. defer file.Close()
    18. //准备写入5句内容
    19. content := "你好,world\r\n"
    20. writer := bufio.NewWriter(file)
    21. for i := 0; i < 5; i++ {
    22. writer.WriteString(content)
    23. }
    24. //因为Writer是带缓冲的,因此在调用WriterString方法时,其实内容是先写入到缓冲的
    25. //所以需要调用Flush方法,将缓冲中的数据真正写入到文件中,否则文件中会丢失数据
    26. writer.Flush()
    27. }

     (4).打开一个存在的文件,将原来的内容读出显示在终端,并且追加5句"你好,北京"

    1. package main
    2. import (
    3. "fmt"
    4. "bufio"
    5. "os"
    6. "io"
    7. )
    8. func main() {
    9. //打开一个存在的文件,将原来的内容读写到终端,并追加内容10句:你好,北京
    10. //打开一个存在文件 "f:/www/test2.txt"
    11. filePath := "f:/www/test2.txt"
    12. file, err := os.OpenFile(filePath, os.O_RDWR | os.O_APPEND, 0666)//O_RDWR 读写模式打开文件, 写操作时将数据附加到文件尾部 O_APPEND
    13. if err != nil {
    14. fmt.Printf("open file err =%v\n", err)
    15. }
    16. //及时关闭
    17. defer file.Close()
    18. //先读取原来内容,并显示在终端
    19. reader := bufio.NewReader(file)
    20. for {
    21. str, err := reader.ReadString('\n')
    22. if err == io.EOF { // 如果读取到文件的末尾
    23. break
    24. }
    25. //显示到终端
    26. fmt.Print(str)
    27. }
    28. //准备写入5句内容
    29. content := "你好,北京\r\n"
    30. writer := bufio.NewWriter(file)
    31. for i := 0; i < 5; i++ {
    32. writer.WriteString(content)
    33. }
    34. //因为Writer是带缓冲的,因此在调用WriterString方法时,其实内容是先写入到缓冲的
    35. //所以需要调用Flush方法,将缓冲中的数据真正写入到文件中,否则文件中会丢失数据
    36. writer.Flush()
    37. }

     方式二

    (1).案例:编写一个程序,将一个文件的内容,写入到另一个文件,注意:这两个文件已经存在了.

    说明:使用ioutil.ReadFile,ioutil.WriterFile完成写文件的任务   

    1. package main
    2. import (
    3. "fmt"
    4. "io/ioutil"
    5. )
    6. func main() {
    7. //将"f:/www/test2.txt" 内容导入 f:/www/test.txt"
    8. //1.首先将test2.txt内容读取到内存
    9. //2.将读取到内容写入f:/www/test.txt
    10. filePath := "f:/www/test2.txt"
    11. file2Path := "f:/www/test.txt"
    12. //ReadFile 从filename指定的文件中读取数据并返回文件的内容
    13. data, err := ioutil.ReadFile(filePath)
    14. if err != nil {
    15. fmt.Printf("read file err= %v", err)
    16. return
    17. }
    18. //函数向filename指定的文件中写入数据。如果文件不存在将按给出的权限创建文件,否则在写入数据之前清空文件。
    19. err = ioutil.WriteFile(file2Path, data, 0666)
    20. if err != nil {
    21. fmt.Println("writer file err= %v", err)
    22. return
    23. }
    24. }

     (2).判断文件/文件夹是否存在

    判断文件或文件夹是否存在的方法为使用os.Stat()函数返回的错误值进行判断:

            1).如果返回的错误为 nil ,说明文件或文件夹存在

            2).如果返回的错误类型使用 os.IsNotExist()判断为 true ,说明文件或文件夹不存在

            3).如果返回的错误为其它类型,则不确定是否在存在

    func Stat 

    1. func Stat(name string) (fi FileInfo, err error)
    2. //Stat返回一个描述name指定的文件对象的FileInfo。如果指定的文件对象是一个符号链接,返回的FileInfo描述该符号链接指向的文件的信息,本函数会尝试跳转该链接。如果出错,返回的错误值为*PathError类型。

     func IsNotExist 

    1. func IsNotExist(err error) bool
    2. //返回一个布尔值说明该错误是否表示一个文件或目录不存在。ErrNotExist和一些系统调用错误会使它返回真
    1. func PathExists(path string) (bool, error) {
    2. _, err := os.Stat(path)
    3. if err == nil { //文件或目录存在
    4. return true, nil
    5. }
    6. if os.IsNotExists(err) {
    7. return false, nil
    8. }
    9. return false, err
    10. }

     (3).拷贝文件

    案例: 将一张图片/电影/mp3拷贝到另外一个文件e/abc.jpg

    io包func Copy():

    函数:

             func Copy(dst Writer, src Reader) (written int64, err error)

    说明:

            将src的数据拷贝到dst,直到在src上到达EOF或发生错误。返回拷贝的字节数和遇到的第一个错误。

    对成功的调用,返回值err为nil而非EOF,因为Copy定义为从src读取直到EOF,它不会将读取到EOF视为应报告的错误。如果src实现了WriterTo接口,本函数会调用src.WriteTo(dst)进行拷贝;否则如果dst实现了ReaderFrom接口,本函数会调用dst.ReadFrom(src)进行拷贝

    注意; copy’函数是 io 包提供的.

    1. package main
    2. import (
    3. "fmt"
    4. "io"
    5. "os"
    6. "bufio"
    7. )
    8. //自己编辑一个函数,接收两个文件路径srcFileName, dstFileName
    9. func Copy(srcFileName string, dstFileName string) (written int64, err error) {
    10. srcFile, err := os.Open(srcFileName)
    11. if err != nil {
    12. fmt.Printf("open file err = %v\n", err)
    13. }
    14. defer srcFile.Close()
    15. //通过srcFile,获取Reader
    16. reader := bufio.NewReader(srcFile)
    17. //打开dstFileName
    18. dstFile, err := os.OpenFile(dstFileName, os.O_WRONLY | os.O_CREATE, 0666)
    19. if err != nil {
    20. fmt.Printf("open file err = %v\n", err)
    21. return
    22. }
    23. //通过dstFile,获取Writer
    24. writer := bufio.NewWriter(dstFile)
    25. defer dstFile.Close()
    26. return io.Copy(writer, reader)
    27. }
    28. func main() {
    29. //将"f:/www/11.png" 拷贝到f:/下"
    30. srcFile := "f:/www/11.png"
    31. dstFile := "f:/11.png"
    32. _, err := Copy(srcFile, dstFile)
    33. if err == nil {
    34. fmt.Println("拷贝完成")
    35. } else {
    36. fmt.Printf("拷贝错误,err = %v\n", err)
    37. }
    38. }

     (4).统计英文,数字,空格和其他字符数量

    说明:

            统计一个文件中含有的英文,数字,空格及其他字符数量

    1. package main
    2. import (
    3. "fmt"
    4. "io"
    5. "os"
    6. "bufio"
    7. )
    8. //定义一个结构体,用于保存统计的结果
    9. type CharCount struct {
    10. ChCount int //记录英文个数
    11. NumCount int //记录数字个数
    12. SpaceCount int //记录空格个数
    13. OtherCount int //记录其他字符个数
    14. }
    15. func main() {
    16. //思路: 打开一个文件,创建一个Reader
    17. //每读一行,就去统计该行有多少英文,数字,空格和其他字符
    18. //然后将结果保存到一个结构体中
    19. fileName := "f:/www/test3.txt"
    20. file, err := os.Open(fileName)
    21. if err != nil {
    22. fmt.Printf("open file err = %v\n", err)
    23. return
    24. }
    25. defer file.Close()
    26. //定义一个CharCount实例
    27. var count CharCount
    28. //创建一个Reader
    29. reader := bufio.NewReader(file)
    30. //循环读取reader里的内容
    31. for {
    32. str, err := reader.ReadString('\n')
    33. if err == io.EOF { //读到文件末尾就退出
    34. break
    35. }
    36. //遍历str,进行统计
    37. //为了兼容中文字符,可以将str转成[]rune
    38. str = []rune(str)
    39. for _, v := range str {
    40. switch {
    41. case v >= 'a' && v <= 'z':
    42. fallthrough //穿透
    43. case v >='A' && v <= 'Z':
    44. count.ChCount++
    45. case v == ' ' || v == '\t':
    46. count.SpaceCount++
    47. case v >='0' && v <= '9':
    48. count.NumCount++
    49. default:
    50. count.OtherCount++
    51. }
    52. }
    53. }
    54. fmt.Printf("字符的个数%v,数字的个数%v,空格的个数%v,其他字符的个数%v\n",
    55. count.ChCount, count.NumCount, count.SpaceCount, count.OtherCount)
    56. }

    三.命令行参数

    基本介绍 

    os.Args是一个string切片,用来存储所有的命令行参数

    var Args []string

    Args保管了命令行参数,第一个是程序名

    1. package main
    2. import(
    3. "fmt"
    4. "os"
    5. )
    6. func main() {
    7. fmt.Println("命令行的参数有:", len(os.Args))
    8. //遍历os.Args切片,就可以得到所有的命令行输入参数值
    9. for i, v := range os.Args {
    10. fmt.Printf("args[%v]=%v\n", i, v)
    11. }
    12. }
    1. PS F:\www\go-data\src\go_code\argsdemo> go build -o test.exe .\main.go
    2. PS F:\www\go-data\src\go_code\argsdemo> .\test.exe tom d:/www 12
    3. 命令行的参数有: 4
    4. args[0]=F:\www\go-data\src\go_code\argsdemo\test.exe
    5. args[1]=tom
    6. args[2]=d:/www
    7. args[3]=12

    flag包用来解析命令行参数

    说明:前面的方式是比较原生的方式,对解析参数不是特别的方便,特别是带有指定参数形式的命令行.

    比如:cmd>main.exe -f c:/aaa.txt -p 200 -u root  这样的形式命令行, go 设计者给我们提供了 fiag 包,可以方便的解析命令行参数,而且参数顺序可以随意

    1. //请编写一段代码,可以获取命令行各个参数
    2. D:/goproject/src/go_code>test.exe -u root -pwd root -h 192.168.1.1 -port 3306
    3. user=root
    4. pwd=root
    5. host=192.168.1.1
    6. port=3306
    1. package main
    2. import (
    3. "fmt"
    4. "flag"
    5. )
    6. func main() {
    7. //定义几个变量,用于接收命令行参数值
    8. var user string
    9. var pwd string
    10. var host string
    11. var port int
    12. //&user: 接收用户输入命令行中输入的 -u 后面的参数
    13. //"u": 就是-u指定参数
    14. //"":默认值
    15. //"用户名,默认为空":参数说明
    16. flag.StringVar(&user, "u", "", "用户名,默认为空")
    17. flag.StringVar(&pwd, "pwd", "", "密码,默认为空")
    18. flag.StringVar(&host, "host", "", "主机,默认为空")
    19. flag.IntVar(&port, "port", 3306, "端口,默认为空")
    20. //很重要的参数,转换,必须调用该方法
    21. flag.Parse()
    22. //输出结果
    23. fmt.Printf("user=%v,pwd=%v,host=%v,port=%v", user, pwd, host, port)
    24. }
    1. #go build -o test.exe
    2. #.\test.exe -u zhangs -pwd 123456
    3. #user=zhangs,pwd=123456,host=,port=3306

     [上一节][go学习笔记.第十一章.项目案例] 2.客户信息管理系统

     [下一节] [go学习笔记.第十二章.文件操作] 2.json基本介绍

  • 相关阅读:
    Maya vs Blender:制作3D动画首选哪一个?
    如何理解MVCC
    物理信息驱动深度学习相关报告总结
    使用Vue.js和Vuex构建可维护的前端应用
    WHAT - reflect-metadata
    (附源码)ssm高校升本考试管理系统 毕业设计 201631
    应用开发平台集成工作流系列之11——流程模板功能设计与实现
    排序-算法
    接口测试--参数实现MD5加密签名规则
    两节点DC-OPF
  • 原文地址:https://blog.csdn.net/zhoupenghui168/article/details/127721049