zoukankan      html  css  js  c++  java
  • Go语言基础之文件操作

    1 文件的基本介绍

    文件,对于我们并不陌生,文件是数据源(保存数据的地方)的一种。文件最主要的作用就是保存数据,它既可以保存一张图片,也可以保存视频、声音等。

    1.1 输入流和输出流

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

    • 流:数据在数据源(文件)和程序(内存)之间经历的路径;
    • 输入流:数据从数据源(文件)到程序(内存)的路径;
    • 输出流:数据从程序(内存)到数据源(文件)的路径。

    1.2 os包

    os包中的File封装所有文件相关操作,其中File是一个结构体。下面列出File结构体的方法以及操作文件相关的函数:

    type File
    func Create(name string) (file *File, err error)
    func Open(name string) (file *File, err error)
    func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
    func NewFile(fd uintptr, name string) *File
    func Pipe() (r *File, w *File, err error)
    func (f *File) Name() string
    func (f *File) Stat() (fi FileInfo, err error)
    func (f *File) Fd() uintptr
    func (f *File) Chdir() error
    func (f *File) Chmod(mode FileMode) error
    func (f *File) Chown(uid, gid int) error
    func (f *File) Readdir(n int) (fi []FileInfo, err error)
    func (f *File) Readdirnames(n int) (names []string, err error)
    func (f *File) Truncate(size int64) error
    func (f *File) Read(b []byte) (n int, err error)
    func (f *File) ReadAt(b []byte, off int64) (n int, err error)
    func (f *File) Write(b []byte) (n int, err error)
    func (f *File) WriteString(s string) (ret int, err error)
    func (f *File) WriteAt(b []byte, off int64) (n int, err error)
    func (f *File) Seek(offset int64, whence int) (ret int64, err error)
    func (f *File) Sync() (err error)
    func (f *File) Close() error
    

    2 文件相关操作

    2.1 打开和关闭文件

    打开和关闭文件使用到的函数和方法:

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

    案例演示:

    import (
    	"fmt"
        "os"
    )
    
    func main() {
        file, err := os.Open("d:/test.txt")
        if err != nil  {
            fmt.Println("open file err=", err)
        }
        
        fmt.Printf("file=%v", file)  //file就是一个指针 *File
        
        //关闭文件
        err = file.Close()
        if err != nil {
            fmt.Println("close file err=", err)
        }
    }
    

    2.2 读文件操作的三种方式

    使用file.Read方法读取文件

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

    该方法接收一个字节切片,返回读取的字节数和可能的错误,读到文件末尾时会返回0io.EOF。示例如下:

    func main() {
    	// 只读方式打开当前目录下的main.go文件
    	file, err := os.Open("./main.go")
    	if err != nil {
    		fmt.Println("open file failed!, err:", err)
    		return
    	}
    	defer file.Close()
    	// 使用Read方法读取数据
    	var tmp = make([]byte, 128)
    	n, err := file.Read(tmp)
    	if err == io.EOF {
    		fmt.Println("文件读完了")
    		return
    	}
    	if err != nil {
    		fmt.Println("read file failed, err:", err)
    		return
    	}
    	fmt.Printf("读取了%d字节数据
    ", n)
    	fmt.Println(string(tmp[:n]))
    }
    

    使用for循环读取文件中的所有数据:

    func main() {
    	// 只读方式打开当前目录下的main.go文件
    	file, err := os.Open("./main.go")
    	if err != nil {
    		fmt.Println("open file failed!, err:", err)
    		return
    	}
    	defer file.Close()
    	// 循环读取文件
    	var content []byte
    	var tmp = make([]byte, 128)
    	for {
    		n, err := file.Read(tmp)
    		if err == io.EOF {
    			fmt.Println("文件读完了")
    			break
    		}
    		if err != nil {
    			fmt.Println("read file failed, err:", err)
    			return
    		}
    		content = append(content, tmp[:n]...)
    	}
    	fmt.Println(string(content))
    }
    

    带缓冲区的方式读写文件。使用到的方法及函数有:

    os.Open()
    file.Close()
    bufio.NewReader()
    reader.ReadString
    

    代码演示:

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    func main() {
    	file, err := os.Open("d:/test.txt")
    	if err != nil {
    		fmt.Println("open file err=", err)
    	}
    
    	// 当函数退出时,要及时关闭file句柄,否则会有内存泄露
    	defer file.Close()
    
    	// 创建一个 *Reader,是带缓冲的
    	reader := bufio.NewReader(file)
    	// 循环读取文件的内容
    	for {
    		str, err := reader.ReadString('
    ')  // 读到一个换行就结束
    		if err == io.EOF {  // io.EOF表示文件的末尾
    			break
    		}
    
    		// 输出内容
    		fmt.Print(str)
    	}
    
    	fmt.Println("文件读取结束...")
    }
    

    一次性将整个文件读入到内存中(这种方式适用于文件不大的情况)。相关方法和函数:

    ioutil.ReadFile()
    

    代码演示:

    package main
    
    import (
    	"fmt"
    	"io/ioutil"
    )
    
    // 一次性将文件内容读取到内存中
    func main()  {
    	file := "d:/test.txt"
    	content, err := ioutil.ReadFile(file)
    	if err != nil {
    		fmt.Println("read file err=%v", err)
    	}
    
    	// 把读取到的内容显示到终端
    	// content的类型是[]byte
    	fmt.Printf("%v", string(content))
    
    	// 在这里不需要显示的打开和关闭文件,因为,文件的Open
    	// 和Close被封装到ReadFile函数内部
    }
    

    2.3 写文件操作

    os.OpenFile()函数能够以指定模式打开文件,从而实现文件写入相关功能。

    func OpenFile(name string, flag int, perm FileMode) (*File, error) {}
    

    其中:

    name:要打开的文件名;

    flag:打开文件的模式,有以下模式:

    模式 含义
    os.O_WRONLY 只写
    os.O_CREATE 创建文件
    os.O_RDONLY 只读
    os.O_RDWR 读写
    os.O_TRUNC 清空
    os.O_APPEND 追加

    prem:文件权限,和Linux中文件的权限控制相同。

    2.3.1 Write和WriteString

    func main() {
    	file, err := os.OpenFile("xx.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
    	if err != nil {
    		fmt.Println("open file failed, err:", err)
    		return
    	}
    	defer file.Close()
    	str := "hello 世界"
    	file.Write([]byte(str))       //写入字节切片数据
    	file.WriteString("hello 小王子") //直接写入字符串数据
    }
    

    2.3.2 bufio.NewWriter

    func main() {
    	file, err := os.OpenFile("xx.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
    	if err != nil {
    		fmt.Println("open file failed, err:", err)
    		return
    	}
    	defer file.Close()
    	writer := bufio.NewWriter(file)
    	for i := 0; i < 10; i++ {
    		writer.WriteString("hello世界
    ") //将数据先写入缓存
    	}
    	writer.Flush() //将缓存中的内容写入文件
    }
    

    2.3.3 ioutil.WriteFile

    func main() {
    	str := "hello 沙河"
    	err := ioutil.WriteFile("./xx.txt", []byte(str), 0666)
    	if err != nil {
    		fmt.Println("write file failed, err:", err)
    		return
    	}
    }
    

    2.4 练习

    • 借助io.copy()实现一个拷贝文件函数:
    package main import (
    	"fmt"
    	"os"
    	"io" 
        "bufio"
    )
    
    
    //自己编写一个函数,接收两个文件路径 srcFileName dstFileName
    func CopyFile(dstFileName string, srcFileName string) (written int64, err error{
    	srcFile, err := os.Open(srcFileName) 
        if err != nil {
    	fmt.Printf("open file err=%v
    ", err)
        }
    	defer srcFile.Close()
    	//通过 srcfile ,获取到 Reader 
        reader := bufio.NewReader(srcFile)
    
        //打开 dstFileName
        dstFile, err := os.OpenFile(dstFileName, os.O_WRONLY | os.O_CREATE, 0666) 
        if err != nil {
            fmt.Printf("open file err=%v
    ", err) 
            return
        }
    
    	//通过 dstFile, 获取到 Writer 
        writer := bufio.NewWriter(dstFile) defer dstFile.Close()
        return io.Copy(writer, reader)
    }
    
    func main() {
    	//将 d:/flower.jpg 文件拷贝到 e:/abc.jpg
    
    	//调用 CopyFile 完成文件拷贝
    	srcFile := "d:/flower.jpg" 
        dstFile := "e:/abc.jpg"
    	_, err := CopyFile(dstFile, srcFile) 
        if err == nil {
    		fmt.Printf("拷贝完成
    ")
        } else {
            fmt.Printf("拷贝错误 err=%v
    ", err)
        }
    }
    
    
    • 统计一个文件中含有的英文、数字、空格及其它字符数量:
    package main import (
    	"fmt"
        "os"
        "io" 
        "bufio"
    )
    
    
    //定义一个结构体,用于保存统计结果 
    type CharCount struct {
        ChCount int // 记录英文个数 
        NumCount int // 记录数字的个数 
        SpaceCount int // 记录空格的个数 
        OtherCount int // 记录其它字符的个数
    }
    
    func main() {
        //思路:  打开一个文件,  创一个 Reader
        //每读取一行,就去统计该行有多少个 英文、数字、空格和其他字符
        //然后将结果保存到一个结构体
        fileName := "e:/abc.txt"
        file, err := os.Open(fileName) 
        if err != nil {
            fmt.Printf("open file err=%v
    ", err) 
            return
        }
        defer file.Close()
        //定义个 CharCount 实例
        var count CharCount
        //创建一个 Reader
        reader := bufio.NewReader(file)
    
    	//开始循环的读取 fileName 的内容
        for {
            str, err := reader.ReadString('
    ')
            if err == io.EOF { //读到文件末尾就退出 
                break
            }
    		//为了兼容中文字符, 可以将 str 转成 []rune  
            str = []run(str)
            //遍历 str ,进行统计
            for _, v := range str {
                switch {
                    case v >= 'a' && v <= 'z':
                    	fallthrough //穿透 
                    case v >= 'A' && v <= 'Z':
                    	count.ChCount++ 
                    case v == ' ' || v == '	':
                    	count.SpaceCount++ 
                    case v >= '0' && v <= '9':
                    	count.NumCount++
                    default :
                    	count.OtherCount++
                }
            }
        }
        //输出统计的结果看看是否正确
        fmt.Printf("字符的个数为=%v 数字的个数为=%v 空格的个数为=%v 其它字符个数=%v",
                   count.ChCount, count.NumCount, count.SpaceCount,count.OtherCount)
    }
    
    • 实现Linux平台cat命令功能
    package main
    
    import (
    	"bufio"
    	"flag"
    	"fmt"
    	"io"
    	"os"
    )
    
    // cat命令实现
    func cat(r *bufio.Reader) {
    	for {
    		buf, err := r.ReadBytes('
    ') //注意是字符
    		if err == io.EOF {
    			break
    		}
    		fmt.Fprintf(os.Stdout, "%s", buf)
    	}
    }
    
    func main() {
    	flag.Parse() // 解析命令行参数
    	if flag.NArg() == 0 {
    		// 如果没有参数默认从标准输入读取内容
    		cat(bufio.NewReader(os.Stdin))
    	}
    	// 依次读取每个指定文件的内容并打印到终端
    	for i := 0; i < flag.NArg(); i++ {
    		f, err := os.Open(flag.Arg(i))
    		if err != nil {
    			fmt.Fprintf(os.Stdout, "reading from %s failed, err:%v
    ", flag.Arg(i), err)
    			continue
    		}
    		cat(bufio.NewReader(f))
    	}
    }
    
  • 相关阅读:
    git命令
    Linux基础知识手册
    Linux系统编程
    A
    Subsequences in Substrings Kattis
    G
    K
    K
    C
    E
  • 原文地址:https://www.cnblogs.com/dabric/p/12397810.html
Copyright © 2011-2022 走看看