• Go语言学习之路第9天(文件操作)


    一.文件操作

    1.1 创建文件

      新建文件可以通过如下方法,Create()方法:

    func Create(name string) (file *File, err error)
    

      Create采用模式0666(任何人都可读写,不可执行,但实际文件权限是由你linux服务器上的umask值决定的)创建一个名为name的文件,如果文件已存在会截断它(为空文件)。如果成功,返回的文件对象可用于I/O;对应的文件描述符具O_RDWR模式。如果出错,错误底层类型是*PathError。

      参数:新创建的文件名;可以绝对路径;也可以相对路径( 相对.go 或 .exe文件。)

      返回值

        file:文件指针。本质:file对象(结构体)

        err:错误返回

      特性

        文件不存在:创建新文件。

        文件存在:覆盖源文件。(截断为0)

      具体实例如下:

    import (
    	"fmt"
    	"os"
    )
    
    func main()  {
    	fw,err := os.Create("./hello.txt")
    	if err != nil {
    		fmt.Println("os.Create err:",err)
    		return
    	}
    
    	defer fw.Close()
    }
    

    1.2 打开文件

      打开文件有两种方式:

      (1)以只读的方式打开文件,Open()方法

    func Open(name string) (file *File, err error)
    

      Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。

      参数:打开的文件名:可以绝对路径;也可以相对路径(相对.go 或 .exe文件。)

      返回值

        file:文件指针。本质:file对象(结构体)

        err:错误返回

      特性

        文件存在:只读打开

        文件不存在:报错返回。

      具体实例如下:

    import (
    	"fmt"
    	"os"
    )
    
    func main()  {
    	fr,err := os.Open("./hello.txt")
    	if err != nil{
    		fmt.Println("os.Open err:",err)
    		return
    	}
    	defer fr.Close()
    }
    

      注意:用Open打开的文件只能用于读取,不能用于写入。

      (2)以读写的方式打开文件,OpenFile()方法

    func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
    

      OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError。

      参数一:打开的文件名:可以绝对路径;也可以相对路径(相对.go 或 .exe文件。)

      参数二:打开文件的操作权限:

        os.O_RDONLY : 只读打开

        os.O_WRONLY : 只写打开

        os.O_RDWR : 读写打开 。 常用

        os.O_APPEND: 追加写

        os.O_CREATE:创建文件

        这里的权限可以进行组合,用 | 分隔,如:

          os.O_RDWR | os.O_CREATE:创建文件并且以读写的方式打开文件

          os.O_RDWR | os.O_APPEND:以读写的方式打开文件并且以追加的方式写(默认的写是覆盖写)

      参数三

        通常传 0

        当参数二为:O_CREATE时,该参数有实际作用:指定新建文件的属性

          权限取值范围(0-7),表示如下:

            0:没有任何权限

            1:执行权限(如果是可执行文件,是可以运行的)

            2:写权限

            3: 写权限与执行权限

            4:读权限

            5: 读权限与执行权限

            6: 读权限与写权限

            7: 读权限,写权限,执行权限

      返回值:

        file:文件指针。本质:file对象(结构体)

        err:错误返回:

      具体案例如下:

    import (
    	"fmt"
    	"os"
    )
    
    func main()  {
    	//创建文件并且以读写的方式打开文件
    	frw,err := os.OpenFile("./hello.txt",os.O_RDWR | os.O_CREATE,0)
    
    	//以读写的方式打开文件并且以追加的方式写
    	//frw,err := os.OpenFile("./hello.txt",os.O_RDWR | os.O_APPEND,0)
    	if err != nil {
    		fmt.Println("os.OpenFile err:",err)
    		return
    	}
    	defer frw.Close()
    }
    

    1.3 关闭文件

    func (f *File) Close() error
    

      Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。

    1.4 写文件

      (1)按字符串写,WriteString()方法

    func (f *File) WriteString(s string) (ret int, err error)
    

      这个方式是由以写的模式打开文件而生成的文件对象调用的。

      参数:待写入文件的字符串

      返回值:

        ret:写入文件的字节数

        err:错误返回

      具体实例如下:

    func main()  {
    	fw,err := os.Create("./hello.txt")
    	if err != nil{
    		fmt.Println("os.Create err:",err)
    		return
    	}
         defer fw.Close() n,err := fw.WriteString("Hello World ") if err != nil{ fmt.Println("fw.WriteString err:",err) return } fmt.Println(n)
           }

      执行之后,hello.txt文件中内容如下:

    Hello World
    

      (2)按位置写

      先确定位置,Seek()方法:

    func (f *File) Seek(offset int64, whence int) (ret int64, err error)
    

      Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。

      参数一:偏移量;矢量:正数向后,负数向前偏。

      参数二:

        0或者io.SeekStart : 从文件起始位置开始偏移。

        1或者io.SeekCurrent: 从当前位置。

        2或者io.SeekEnd: 从文件末尾位置开始偏移。

      返回值:

        ret:较文件起始位置,偏过的字节数。

        err:错误返回

      然后根据的得到的偏移量来写文件,WriteAt()方法:

    func (f *File) WriteAt(b []byte, off int64) (n int, err error)
    

      WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

      参数一:待写入文件的数据内容,是字符切片类型。

      参数二:偏移量;Seek函数的返回值ret。

      返回值:

        n:写入文件的字节

        err:错误返回

      具体实例如下:

    func main()  {
    	fw,err := os.OpenFile("./hello.txt",os.O_RDWR,0)
    		if err != nil{
    			fmt.Println("os.OpenFile err:",err)
    			return
    	}
    	defer fw.Close()
    
    	//位置偏移到末尾
    	ret,err := fw.Seek(0,io.SeekEnd)
    	if err != nil{
    		fmt.Println("fw.Seek err:",err)
    		return
    	}
    
    	n,err := fw.WriteAt([]byte("This is a Go Program
    "),ret)
    	if err != nil{
    		fmt.Println("fw.WriteAt err:",err)
    		return
    	}
    
    	fmt.Println(n)
    }
    

      执行完后hello.txt中的内容是:

    Hello World
    This is a Go Program
    

      (3)按字符写,Write()方法

    func (f *File) Write(b []byte) (n int, err error)
    

      Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

      参数:待写入文件的数据内容

      返回值:

        n:写入的字节个数

        err:错误处理

      具体实例如下:

    func main()  {
    	//以读写方式打开文件并以追加的方式写
    	fw,err := os.OpenFile("./hello.txt",os.O_RDWR | os.O_APPEND,0)
    		if err != nil{
    			fmt.Println("os.OpenFile err:",err)
    			return
    	}
    	defer fw.Close()
    
    	n,err := fw.Write([]byte("Good Good Study,Day Day Up
    "))
    	if err != nil{
    		fmt.Println("fw.Write err:",err)
    		return
    	}
    	fmt.Println(n)
    
    }
    

      执行完后,hello.txt文件中内容如下:

    Hello World
    This is a Go Program
    Good Good Study,Day Day Up
    

    1.5 读文件

      (1)按行读文件

      可以通过两步来实现。

      首先,创建一个带有缓冲区的Reader,使用bufio包下的NewReader()函数来实现。

    func NewReader(rd io.Reader) *Reader
    

       NewReader创建一个具有默认大小缓冲、从r读取的*Reader。

      参数:文件指针(open、Create、OpenFile 返回值)

      返回值:带有缓冲区的阅读器

      然后,从Reader 自带的缓冲区中,按指定的“分隔符(delim)”获取数据。我们通常使用ReadBytes(‘ ’) 来有效的提取一行数据。

    func (b *Reader) ReadBytes(delim byte) (line []byte, err error)
    

      ReadBytes读取直到第一次遇到delim字节,返回一个包含已读取的数据和delim字节的切片。如果ReadBytes方法在读取到delim之前遇到了错误,它会返回在错误之前读取的数据以及该错误(一般是io.EOF)。当且仅当ReadBytes方法返回的切片不以delim结尾时,会返回一个非nil的错误。

      读到的数据成功保存在返回的[]byte 中。可以循环按行读取整个文件。

      参数:分隔符,一般都是' ',Linux系统中的行结束标记。

      返回值:

        line:实际读到的一行数据,是字符切片类型

        err:错误处理

      文件结尾:EOF —— end of file

        当读到文件末尾时,err 会被置为 io.EOF

      具体实例如下:

    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func main()  {
    	fr,err := os.Open("./hello.txt")
    	if err != nil{
    		fmt.Println("os.Open err:",err)
    		return
    	}
    
    	defer fr.Close()
    
    	reader := bufio.NewReader(fr)
    	for{
    		line,err := reader.ReadBytes('
    ')
    		if err != nil{
    			if err == io.EOF{
    				fmt.Println("文件已读完")
    				break
    			}else {
    				fmt.Println("reader.ReadBytes err:",err)
    				return
    			}
    		}
    		fmt.Print(string(line))
    	}
    }
    

      结果如下:

    Hello World
    This is a Go Program
    Good Good Study,Day Day Up
    文件已读完
    

      (2)按字节读,Read()方法

    func (b *Reader) Read(p []byte) (n int, err error)
    

      Read读取数据写入p。本方法返回写入p的字节数。本方法一次调用最多会调用下层Reader接口一次Read方法,因此返回值n可能小于len(p)。读取到达结尾时,返回值n将为0而err将为io.EOF。

      参数:空缓冲区(需要自己创建),用来存放read读到的数据内容。

      返回值:

        n:实际读到的字节个数

        err:错误处理

      具体实例如下:

    func main()  {
    	fr,err := os.Open("./hello.txt")
    	if err != nil{
    		fmt.Println("os.Open err:",err)
    		return
    	}
    	defer fr.Close()
    
    	//自定义缓冲区
    	slice := make([]byte,4096)
    
    	for{
    		n,err := fr.Read(slice)
    		if err != nil{
    			if err == io.EOF{
    				fmt.Println("文件已读完")
    				break
    			}else {
    				fmt.Println("fr.Read err:",err)
    				return
    			}
    		}
    		fmt.Print(string(slice[:n]))
    	}
    }
    

      得到结果如下:

    Hello World
    This is a Go Program
    Good Good Study,Day Day Up
    文件已读完
    

    1.6 大文件拷贝

      文件拷贝的核心思想就是读多少就写多少

    import (
    	"fmt"
    	"io"
    	"os"
    )
    
    func main()  {
    	//以只读的方式打开待源文件
    	fr,err := os.Open("./01-复习.avi")
    	if err != nil{
    		fmt.Println("os.Open err:",err)
    		return
    	}
    	defer fr.Close()
    
    	//以写的方式打开目标文件
    	fw,err := os.Create("./复习.avi")
    	if err != nil{
    		fmt.Println("os.Create err:",err)
    		return
    	}
    
    	//创建缓冲区
    	buf := make([]byte,4096)
    
    	//循环读取源文件内容,然后读取多少就往目标文件写多少
    	for{
    		n,err := fr.Read(buf)
    		if err != nil{
    			if err == io.EOF{
    				fmt.Println("文件以拷贝完毕")
    				break
    			}else {
    				fmt.Println("fr.Read err:",err)
    				return
    			}
    		}
    		_,err = fw.Write(buf[:n])
    		if err != nil{
    			fmt.Println("fw.Write err:",err)
    			return
    		}
    	}
    
    }
    

    二.目录操作 

    我们读写的文件一般存放于目录中。因此,有时需要指定到某一个目录下,根据目录存储的状况再进行文件的特定操作。接下来我们看看目录的基本操作方法。

    (1) 打开目录,OpenFile()方法

    func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
    

    参数一:绝对或相对路径名

    参数二:O_RDONLY

    参数三:os.ModeDir

    返回值:

      file:指向目录的文件指针

      err:错误处理

    (2)读目录内容,Readdir()方法

    这与读文件有所不同。目录中存放的是文件名和子目录名。所以使用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构成的切片和该错误。

    参数:取的目录项个数, -1 表示所有。

    返回值:

      fi:FileInfo类型的切片。其内部保存了文件名。

      err:错误信息。

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

    得到FileInfo类型切片后,我们可以range遍历切片元素,使用.Name()获取文件名。使用.Size()获取文件大小,使用.IsDir()判断文件是目录还是非目录文件。

    如:我们可以提示用户提供一个目录位置,打开该目录,查看目录下的所有成员,并判别他们是文件还是目录。

    示例如下:

    import (
    	"fmt"
    	"os"
    )
    
    func main()  {
    	fmt.Print("请输入要找寻的目录:")
    	var path string
    	fmt.Scan(&path)
    
    	dir,err := os.OpenFile(path,os.O_RDONLY,os.ModeDir)
    	if err != nil{
    		fmt.Println("os.OpenFile err:",err)
    		return
    	}
    
    	s,err := dir.Readdir(-1)
    	if err != nil{
    		fmt.Println("dir.Readdir:",err)
    		return
    	}
    
    	for _,data := range s{
    		if data.IsDir(){
    			fmt.Println(data.Name(),"是一个目录。")
    		}else {
    			fmt.Println(data.Name(),"是一个文件。")
    		}
    	}
    }
    
     
     
     
     
  • 相关阅读:
    每日总结
    每日总结
    每日总结
    每日总结
    每日总结
    每日总结
    每日总结
    实现微信小程序和支付宝小程序二维码合并
    Solr教程:1.下载和安装
    如何生成漫画风图片无需下载APP无需PS无需电脑
  • 原文地址:https://www.cnblogs.com/dacaigouzi1993/p/11137545.html
Copyright © 2020-2023  润新知