Go语言文件读写

1.文件打开和读取

1.文件定义

  • 文件是存储在外部介质上的数据集合
    • 文件分类:文本文件和二进制文件
    • 文件存取方式:随机存取和顺序存取

2.打开文件

package main

import (
    "fmt"
    "os"
)

func main()  {
    // 只读方式打开文件
    file, err := os.Open("../io/main.go")
    if err != nil {
	fmt.Printf("open file err: %v\n", err)
	return
    }
    defer file.Close()
}

3.文件读取

  • file.Read:从当前位置读取
// 定义一个字节类型的切片(引用类型)
var buf[128]byte
n, _ := file.Read(buf[:])  // 将读取到的内容塞到buf中,返回读取到的字节长度和err
fmt.Println("read length: ", n)
fmt.Println("data: ", string(buf[:]))
  • 读取全部内容
var content []byte
for {
    // 定义一个字节类型的切片(引用类型)
    var buf[128]byte
    // Read方法类似于python中字典的pop方法,从file中删除每次读取得到的内容,这样下次读取就直接从未读取的部分开始截取
    _, err := file.Read(buf[:])  // 将读取到的内容塞到buf中,返回读取到的字节长度和err
    if err == io.EOF {
	// 文件已读取完成
	break
    }
    if err != nil {
	fmt.Println("read file err: ", err)
	return
    }
    // 将每次读取的字节数组追加到content中
    content = append(content, buf[:]...)
}
fmt.Println(string(content))
  • file.ReadAt:从指定位置读取
var buf[64]byte
// 跳过前128字节,读取64字节内容
n, _ := file.ReadAt(buf[:], 128)
fmt.Println(n)
fmt.Println(string(buf[:]))
  • 读到文件末尾返回io.EOF

4.使用bufio读取文件

  • 使用bufio可以实现按行读取文件
reader := bufio.NewReader(file)
line, err := reader.ReadString('\n')
fmt.Println(line)
  • 按行读取整个文件
reader := bufio.NewReader(file)
for {
    line, err := reader.ReadString('\n')
    if err == io.EOF {
	break
    }
    if err != nil {
	fmt.Println("bufio read failed: ", err)
    }
    fmt.Print(line)
}

4.使用ioutil读取文件

  • 可以直接读取整个文件
package main

import (
    "fmt"
    "io/ioutil"
)

func main()  {
    content, err := ioutil.ReadFile("../io/main.go")
    if err != nil {
	fmt.Println("ioutil read file error: ", err)
	return
    }
    fmt.Println(string(content))
}
// 内置方法打开文件
file, err := os.Open("../io/main.go")
if err != nil {
    fmt.Printf("open file err: %v\n", err)
    return
}
// 使用ioutil从文件对象中直接读取全部内容
content, err := ioutil.ReadAll(file)
if err != nil {
    fmt.Println("ioutil read file error: ", err)
    return
}
fmt.Println(string(content))

5.读取压缩文件

  • 1.直接读取
package main

import (
    "compress/gzip"
    "fmt"
    "io"
    "os"
)

func main()  {
    file, err := os.Open("./aaaa.txt.gz")
    if err != nil {
	fmt.Printf("open file err: %v\n", err)
	return
    }
    defer file.Close()

    reader, errs := gzip.NewReader(file)
    if errs != nil {
	fmt.Println("gzip new reader failed: ", errs)
	return
    }
    var content []byte
    var buf [128]byte
    for {
	length, err := reader.Read(buf[:])
	if err == io.EOF {  // 一定要在 nil 前判断
    	    break
	}
	if err != nil {
	    fmt.Println("read file error: ", err)
	    return
	}
	content = append(content, buf[:length]...)
    }
    fmt.Println(string(content[:]))
}
  • 2.使用ioutil读取
package main

import (
    "compress/gzip"
    "fmt"
    "io"
    "os"
)

func main()  {
    file, err := os.Open("./aaaa.txt.gz")
    if err != nil {
	fmt.Printf("open file err: %v\n", err)
	return
    }
    defer file.Close()

    fz, errs := gzip.NewReader(file)
    if errs != nil {
	fmt.Println("gzip new reader failed: ", errs)
	return
    }
    
    content, errs := ioutil.ReadAll(fz)
    if errs != nil {
	fmt.Println("ioutil read file error: ", errs)
	return
    }
    fmt.Println(string(content))
}

2.文件打开和写入

1.os.OpenFile(name, mode, perm)

  • name: 文件路径
  • mode:打开模式
    • os.O_WRONLY:只写
    • os.O_CREATE:创建文件
    • os.O_RDONLY:只读
    • os.O_RDWR:读写
    • os.O_TRUNC:清空
    • os.O_APPEND:追加
  • perm:操做权限
    • r:004
    • w:002
    • x:001

2.文件写入示例

  • 1.file.Write():直接往文件中写入二进制
package main

import (
    "fmt"
    "os"
)

func main()  {
    // 文件不存在时创建,存在时清空,以读写方式打开
    // 如果不清空,再次打开写入时默认是从最开始写入的
    file, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666)
    if err != nil {
	fmt.Println("open file error: ", err)
	return
    }
    defer file.Close()
    file.Write([]byte("这是一个测试"))
}
  • 2.file.WriteAt():往文件指定位置写入二进制
  • 3.file.WriteString():直接往文件写入字符串
// 使用bufio写入文件
package main

import (
    "fmt"
    "os"
)

func main()  {
    // 文件不存在时创建,存在时清空,以读写方式打开
    // 如果不清空,再次打开写入时默认是从最开始写入的
    file, err := os.OpenFile("./test.txt", os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666)
    if err != nil {
	fmt.Println("open file error: ", err)
	return
    }
    defer file.Close()
    //bufio.NewWriterSize()
    bfd := bufio.NewWriter(file)  // 调用的也是NewWriterSize,默认写入大小是4096
    writeData1 := "hello world"
    writeData2 := " my name is lucy"
    bfd.WriteString(writeData1)
    bfd.WriteString(writeData2)
    // 清空缓冲区,进行缓冲区内容落到磁盘
    bfd.Flush()
}
  • 4.使用ioutil写入全文件
package main

import (
    "fmt"
    "io/ioutil"
)

func main()  {
    str := "hello world"
    err := ioutil.WriteFile("./test.txt", []byte(str), 0755)
    if err != nil {
	fmt.Println("write file err: ", err)
	return
    }
}

3.文件拷贝

  • io.Copy(dst, src):文件拷贝
    • dst:结果文件
    • src:源文件
package main

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

func CopyFile(dstName, srcName string) (written int64, err error) {
    src, err := os.Open(srcName)
    if err != nil {
	fmt.Println("源文件打开失败:", err)
	return
    }
    defer src.Close()

    dst, errs := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
    if errs != nil {
	fmt.Println("目标文件读取失败:", err)
	return
    }
    defer dst.Close()
    return io.Copy(dst, src)
}

func main()  {
    CopyFile("test2.txt", "test.txt")
    fmt.Println("Copy done")
}

4.defer详解

  • 示例一:
package main

import "fmt"

func test() int {
    x := 5
    defer func() {
	x += 1
	fmt.Println("我被调用了,", x)
    }()
    fmt.Println("defer 在后面执行")
    return x
}
func main()  {
    fmt.Println(test())
}

/*
defer 在后面执行
我被调用了, 6
5
*/
  • 示例二:
package main

import "fmt"

func test() (x int) {
    defer func() {
	x += 1
	fmt.Println("我被调用了,", x)
    }()
    fmt.Println("defer 在后面执行")
    return 5
}
func main()  {
    fmt.Println(test())
}

/*
defer 在后面执行
我被调用了, 6
6
*/

5.Go语言路径

  • 1.直接使用goland运行程序,则当前路径是src
  • 2.命令行运行程序,当前路径就是运行程序文件所在的路径
  • 3.运行go install命令打包后的.exe,当前路径就是bin

6.实现tree命令

package main

import (
    "fmt"
    "github.com/urfave/cli"
    "io/ioutil"
    "os"
    "path/filepath"
)

/*
|---files                     最顶层:fmt.Printf("!---%s\n", filepath.Base(path))
|    |----xxx.xx              文件:fmt.Printf("|")    fmt.Printf("    |")    fmt.Printf("----%s\n", fi.Name())
|    |    |----xxx            文件夹:if fi.IsDir()   fmt.Printf("|")    for i:=0;i < deep; i++{fmt.Printf("    |")}    fmt.Printf("----%s\n", fi.Name())
go run tree.go ..\..\dcpuffer
*/
func ListDir(path string, deep int) (err error) {
    dir, err := ioutil.ReadDir(path)  // 获取路径下的所有文件和文件夹
    if err != nil {
	return err
    }
    if deep == 1{
	// filepath.Base(path) 例如:F:\project\golearn\src\dcpuffer\files  ---> files
	// 1.如果deep为1,先打印出 |---files
	fmt.Printf("!---%s\n", filepath.Base(path))
    }
    // os.PathSeparator:windows目录分割符是 \
    // os.PathSeparator:linux的目录分隔符是 /
    sep := string(os.PathSeparator)
    for _, fi := range dir {
        // 如果fi是目录,继续调用ListDir进行遍历
	if fi.IsDir() {  // 2.如果是目录,则输出|
	    fmt.Printf("|")
	    for i := 0; i < deep; i++{
	        fmt.Printf("    |")
	    }
	    fmt.Printf("----%s\n", fi.Name())
	    ListDir(path+sep+fi.Name(), deep+1)
	    continue
	}
	fmt.Printf("|")
	for i := 0; i < deep; i++ {
	    fmt.Printf("    |")
	}
	fmt.Printf("----%s\n", fi.Name())
    }
    return nil
}
func main()  {
    app := cli.NewApp()
    app.Name = "tree"
    app.Usage = "list all files"
	
    app.Action = func(c *cli.Context) error {
	dir := "."  // 如果用户未传递路径,则使用当前路径作为目标
	if c.NArg() > 0 {
	    dir = c.Args()[0]
	}
	ListDir(dir, 1)
	return nil
    }
    app.Run(os.Args)
}
posted @ 2022-09-23 09:35  fatpuffer  阅读(337)  评论(0)    收藏  举报