Golang 文件操作

1. 读文件

  • os.Open(name string) (file *File, err error)
  • os.OpenFile(name string, flag int, perm FileMode) (*File, error)
  • ioutil.ReadFile(name string) ([]byte, error)

1.1 带缓存读

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

	reader := bufio.NewReader(file)
	for {
		// 按行读取
		line, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		}
		fmt.Print(line)
	}
}

1.2 一次性读

适合配置文件等小文件

func main() {
	bs, err := ioutil.ReadFile("./abc.txt")
	if err != nil {
		fmt.Printf("Read file error: %v\n", err)
		return
	}

	fmt.Printf("%s\n", bs)
}

1.3 分片读取

func main() {
	file, err := os.Open("abc.txt")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	for {
		buf := make([]byte, 32)
		_, err = file.Read(buf)
		if err == io.EOF {
			break
		}

		if err != nil {
			panic(err)
		}

		fmt.Printf("%s", buf)
	}
}

1.4 寻址 seek

寻址标记 whence: 0-begin, 1-current, 2-end

file, _ := os.Open("abc.txt")
	defer file.Close()

	// 开始位置前进5个字节
	var whence = 0
	var offset int64 = 5
	pos, _ := file.Seek(offset, whence)
	fmt.Println("Jump forward 5 bytes from start position:", pos)

	// 当前位置回退2个字节
	whence = 1
	offset = -2
	pos, _ = file.Seek(offset, whence)
	fmt.Println("Jump back 2 bytes from current position:", pos)
}

1.5 分隔符读取

  • bufio.NewScanner(r io.Reader) *Scanner
func main() {
	file, _ := os.Open("abc.txt")
	defer file.Close()

	scanner := bufio.NewScanner(file)

	// 分隔函数,默认 bufio.ScanLines
	scanner.Split(bufio.ScanWords)

	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}

	err := scanner.Err()
	if err != nil {
		panic(err)
	}
}

1.6 按行读取

func main() {
	file, err := os.Open("abc.txt")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// 放入缓冲读
	reader := bufio.NewReader(file)

	for {
		// 自动丢失结尾符 \n
		line, _, err := reader.ReadLine()
		if err == io.EOF {
			break
		}
		if err != nil {
			panic(err)
		}

		fmt.Printf("%s\n", line)
	}
}

2. 写文件

  • os.OpenFile(name string, flag int, perm FileMode) (file *File, err error)
  • os.Create(name string) (*File, error)
  • io/ioutil.Write(filename string, data []byte, perm fs.FileMode) error

文件操作模式:

  • 覆盖写:os.O_WRONLY | os.O_TRUNC
  • 追加写:os.O_WRONLY | os.O_APPEND
  • 读写并追加:os.O_RDWR | os.OS_APPEND

2.1. 常规写

func writeFile() {
	file, err := os.OpenFile("abc.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0644)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	byteSlice := []byte("hello world!")
	bytesWritten, err := file.Write(byteSlice)
	if err != nil {
		panic(err)
	}
	fmt.Printf("Wrote %d bytes\n", bytesWritten)
}

2.2 快速写

覆盖写:

func main() {
	err := ioutil.WriteFile("abc.txt", []byte("add a new line"), 0644)
	if err != nil {
		panic(err)
	}
}

2.3 缓冲写

bufio 包:

func NewWriter(w io.Writer) *Writer
func NewWriterSize(w io.Writer, size int) *Writer

func (b *Writer) Write(p []byte) (nn int, err error)
func (b *Writer) WriteString(s string) (int, error)
func (b *Writer) WriteByte(c byte) error
func (b *Writer) WriteRune(r rune) (size int, err error)

func (b *Writer) Flush() error
func bufferedWrite() {
	file, err := os.OpenFile("abc.txt", os.O_WRONLY, 0644)
	if err != nil {
		panic(err)
	}
	defer file.Close()

	// 缓冲写
	bufferedWriter := bufio.NewWriter(file)

	// 写入字节
	bytesWritten, err := bufferedWriter.Write([]byte{65, 66, 47, '\n'})
	if err != nil {
		panic(err)
	}
	fmt.Printf("Bytes written: %d\n", bytesWritten)

	// 写入字符串
	bytesWritten, err = bufferedWriter.WriteString("Buffered string\n")
	if err != nil {
		panic(err)
	}
	fmt.Printf("Bytes written: %d\n", bytesWritten)

	// 缓冲中的字节数
	unflushedBufferSize := bufferedWriter.Buffered()
	fmt.Printf("Bytes buffered: %d\n", unflushedBufferSize)

	// 未使用缓存的大小
	bytesAvailable := bufferedWriter.Available()
	fmt.Printf("Available buffer: %d\n", bytesAvailable)

	// 写入磁盘
	bufferedWriter.Flush()

	// 重置缓存写,将丢弃缓存内容
	bufferedWriter.Reset(bufferedWriter)

	bytesAvailable = bufferedWriter.Available()
	fmt.Printf("Available buffer after reset: %d\n", bytesAvailable)

	// 重置缓存大小
	bufferedWriter = bufio.NewWriterSize(bufferedWriter, 8000)

	// 重置后的缓存大小
	bytesAvailable = bufferedWriter.Available()
	fmt.Printf("Available buffer after set buffered size: %d\n", bytesAvailable)
}

简单:

func main() {
	file, err := os.OpenFile("abc.txt", os.O_CREATE|os.O_WRONLY, 0600)
	if err != nil {
        panic(err)
	}
	defer file.Close()

	msg := "Hello World!\n"

	writer := bufio.NewWriter(file)
	for i := 0; i < 5; i++ {
		writer.Write([]byte(msg))
	}
	writer.Flush()
}

3. 拷贝文件

3.1 直接拷贝

适合小文件、文本文件

func main() {
	bs, err := ioutil.ReadFile("abc.txt")
	if err != nil {
        panic(err)
	}

	err = ioutil.WriteFile("abc.txt", bs, 0600)
	if err != nil {
		 panic(err)
	}
}

3.2 缓冲拷贝

io 包,适合大文件、二进制文件:

// 默认缓冲区大小
func Copy(dst Writer, src Reader) (written int64, err error)

// 自定义缓冲区大小
func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error)
func CopyFile(dstFileName, srcFileName string) (written int64, err error) {
	srcFile, err := os.OpenFile(srcFileName, os.O_RDONLY, 0)
	if err != nil {
		return 0, err
	}
	defer srcFile.Close()

	dstFile, err := os.OpenFile(dstFileName, os.O_CREATE|os.O_WRONLY, 0600)
	if err != nil {
		return 0, err
	}
	defer dstFile.Close()

	writer := bufio.NewWriter(dstFile)
	reader := bufio.NewReader(srcFile)

	written, err = io.Copy(writer, reader)
    
    // flush to disk
	err = writer.Sync()
	if err != nil {
		return 0, err
	}

	return
}

4. 统计文件

4.1 文件信息

func statFile() {
	fileInfo, err := os.Stat("abc.txt")
	if err != nil {
        // 判断文件是否存在
		if os.IsNotExist(err) {
			fmt.Println("file not exist")
		}
		panic(err)
	}

	fmt.Println("File name:", fileInfo.Name())
	fmt.Println("Size in bytes:", fileInfo.Size())
	fmt.Println("Permissions:", fileInfo.Mode())
	fmt.Println("Last modified:", fileInfo.ModTime())
	fmt.Println("Is directory:", fileInfo.IsDir())
	fmt.Printf("System interface type: %T\n", fileInfo.Sys())
	fmt.Printf("System info: %+v\n", fileInfo.Sys())
}

4.1 字符统计

type Statistic struct {
	Char   int
	Number int
	Space  int
	Other  int
}

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

	stat := Statistic{}

	reader := bufio.NewReader(file)
	for {
		bs, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		}

		for _, c := range []rune(bs) {
			switch {
			case c >= 'a' && c <= 'z':
				fallthrough
			case c >= 'A' && c <= 'Z':
				stat.Char++
			case c >= '0' && c <= '9':
				stat.Number++
			case c == ' ' || c == '\t':
				stat.Space++
			default:
				stat.Other++
			}
		}
	}

	fmt.Printf("%v\n", stat)
}

5. 目录遍历

filepath 包:

  • type WalkFunc func(path string, info os.FileInfo, err error) error
  • func Walk(root string, walkFn WalkFunc) error
func main() {
	err := filepath.Walk("/tmp", walkFunc)
	if err != nil {
		panic(err)
	}
}

func walkFunc(path string, info fs.FileInfo, err error) error {
	fmt.Println(path)

	return nil
}

7. 压缩文件

7.1 zip

7.1.1 压缩

func zipCompress() {
	target := "/var/log"
	zipFilename := fmt.Sprintf("%s.zip", filepath.Base(target))

	// 压缩文件
	writer, err := os.Create(zipFilename)
	if err != nil {
		log.Fatal(err)
	}
	defer writer.Close()

	err = CompressZip(target, writer)
	if err != nil {
		log.Fatal(err)
	}
}

func CompressZip(rootDir string, writer io.Writer) (err error) {
	// writer
	zipWriter := zip.NewWriter(writer)
	defer zipWriter.Close()

	// 遍历写入文件
	err = filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 压缩包头信息
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		// 文件名,去除最外层的
		header.Name = strings.TrimPrefix(path, filepath.Dir(rootDir))
		if info.IsDir() {
			header.Name += "/"
		}

		// 普通文件,进行压缩
		if info.Mode().IsRegular() {
			header.Method = zip.Deflate
		}

		// 创建压缩包头信息
		fileWriter, err := zipWriter.CreateHeader(header)
		if err != nil {
			return err
		}

		// 非文件,直接返回
		if !info.Mode().IsRegular() {
			return nil
		}

		// 打开待压缩的文件
		reader, err := os.Open(path)
		if err != nil {
			return err
		}
		defer reader.Close()

		// 写入文件
		_, err = io.Copy(fileWriter, reader)

		return err
	})

	return
}

7.1.2 解压

func zipExtract() {
	zipFilename := `C:\Users\MSN\Downloads\log.zip`

	// 解压文件
	err := ExtractZip(zipFilename)
	if err != nil {
		log.Fatal(err)
	}
}


func ExtractZip(zipFilename string) error {
	baseDir := filepath.Dir(zipFilename)

	zipReader, err := zip.OpenReader(zipFilename)
	if err != nil {
		return err
	}
	defer zipReader.Close()

	for _, file := range zipReader.Reader.File {
		err = func(file *zip.File) error {
			zippedFile, err := file.Open()
			if err != nil {
				return err
			}
			defer zippedFile.Close()

			extractedFilePath := filepath.Join(baseDir, file.Name)

			if file.FileInfo().IsDir() {
				err = os.MkdirAll(extractedFilePath, file.Mode())
				if err != nil {
					return err
				}
			} else if file.FileInfo().Mode().IsRegular() {
				outputFile, err := os.OpenFile(extractedFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, file.Mode())
				if err != nil {
					return err
				}
				defer outputFile.Close()

				_, err = io.Copy(outputFile, zippedFile)
				if err != nil {
					return err
				}
			} else {
				log.Printf("unknown type: %c in %s\n", file.Mode().Type(), file.Name)
			}

			return nil
		}(file)

		if err != nil {
			return err
		}
	}

	return nil
}

7.2 tar & gzip

7.2.1 压缩

func tgzCompress() {
	target := "/var/log"
	tgzFilename := fmt.Sprintf("%s.tar.gz", filepath.Base(target))

	// 压缩文件
	writer, err := os.Create(tgzFilename)
	if err != nil {
		log.Fatal(err)
	}
	defer writer.Close()

	err = CompressTarGz(target, writer)
	if err != nil {
		log.Fatal(err)
	}
}

func CompressTarGz(rootDir string, writer io.Writer) (err error) {
	gzipWriter := gzip.NewWriter(writer)
	defer gzipWriter.Close()

	tarWriter := tar.NewWriter(gzipWriter)
	defer tarWriter.Close()

	// 遍历写入文件
	err = filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		var link string
		if info.Mode()&os.ModeSymlink == os.ModeSymlink {
			if link, err = os.Readlink(path); err != nil {
				return err
			}
		}

		// 压缩包头信息
		header, err := tar.FileInfoHeader(info, link)
		if err != nil {
			return err
		}

		// 文件名,去除最外层的
		header.Name = strings.TrimPrefix(path, filepath.Dir(rootDir))

		// 创建压缩包头信息
		err = tarWriter.WriteHeader(header)
		if err != nil {
			return err
		}

		// nothing more to do for non-regular
		if !info.Mode().IsRegular() {
			return nil
		}

		// 打开待压缩的文件
		reader, err := os.Open(path)
		if err != nil {
			return err
		}
		defer reader.Close()

		// 写入文件
		_, err = io.Copy(tarWriter, reader)

		return err
	})

	return
}

7.2.2 解压

func tgzExtract() {
	tgzFilename := `C:\Users\MSN\Downloads\log.tar.gz`
	baseDir := filepath.Dir(tgzFilename)

	// 解压文件
	reader, err := os.Open(tgzFilename)
	if err != nil {
		log.Fatal(err)
	}
	defer reader.Close()

	err = ExtractTarGz(reader, baseDir)
	if err != nil {
		log.Fatal(err)
	}
	reader.Close()
}

func ExtractTarGz(reader io.Reader, baseDir string) error {
	gzipReader, err := gzip.NewReader(reader)
	if err != nil {
		return err
	}

	tarReader := tar.NewReader(gzipReader)

	for {
		header, err := tarReader.Next()
		if err == io.EOF {
			break
		}
		if err != nil {
			return err
		}

		filename := filepath.Join(baseDir, header.Name)

		switch header.Typeflag {
		case tar.TypeDir:
			if err = os.MkdirAll(filename, fs.FileMode(header.Mode)); err != nil {
				return err
			}
		case tar.TypeReg:
			outFile, err := os.OpenFile(filename, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fs.FileMode(header.Mode))
			if err != nil {
				return err
			}
			_, err = io.Copy(outFile, tarReader)
			if err != nil {
				return err
			}
			outFile.Close()
		default:
			log.Printf("unknown type: %c in %s\n", header.Typeflag, header.Name)
		}
	}

	return nil
}

8. 临时文件

未指定目录时,在系统临时目录下创建,名称随机的

func main() {
	tmpDir, err := ioutil.TempDir("", "temp")
	if err != nil {
		panic(err)
	}
	defer os.RemoveAll(tmpDir)

	tmpFile, err := ioutil.TempFile(tmpDir, "tmp.txt")
	if err != nil {
		panic(err)
	}
	defer tmpFile.Close()

	var i byte
	for i = 0; i < 127; i++ {
		_, err = tmpFile.Write([]byte{i})
		if err != nil {
			panic(err)
		}
	}
}

9. 其他操作

// 清空文件 100 bytes
err := os.Truncate("abc.txt", 100)

// 重命名
err := os.Rename(oldPath, newPath)

// 删除文件
err := os.Remove("abc.txt")

// 文件权限
err := os.Chmod("abc.txt", 0700)

// 文件所有者
err := os.Chown("abc.txt", os.Getuid(), os.Getgid())

// 文件时间戳
lastAccessTime := time.Now().Add(30 * time.Second)
lastModifyTime := time.Now().Add(-2 * time.Hour)
err := os.Chtimes("abc.txt", lastAcessTime, lastModifyTime)

// 硬链接
err := os.Link("abc.txt", "abc.txt.1")

// 软链接
err := os.Symlink("abc.txt", "abc_sym.txt")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值