Golang 文件操作

读取

  1. 一次性读取
go 复制代码
data, err := os.ReadFile("filename.txt")
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(data))
  1. 按行读取

方式1:bufio.NewScanner

go 复制代码
file, err := os.Open("filename.txt")
if err != nil {
	panic(err)
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
	fmt.Println(scanner.Text())
}

if err := scanner.Err(); err != nil {
	log.Fatal(err)
}

方式2:bufio.NewReader

go 复制代码
file, err := os.Open("filename.txt")
if err != nil {
	panic(err)
}
defer file.Close()

reader:= bufio.NewReader(file)
for {
	line, _, err := reader.ReadLine()
	if err == io.EOF {
		break
	}
	fmt.Println(string(line))
}

区别是bufio.Scanner 还可自定义扫描的分隔符,如:

go 复制代码
file, _ := os.Open("filename.txt")
scanner := bufio.NewScanner(file)
//scanner.Split(bufio.ScanLines) // 按行读,是默认读取方式
//scanner.Split(bufio.ScanWords) // 按单词读,返回文本中每个以空格分隔的单词,并删除周围的空格
//scanner.Split(bufio.ScanBytes) // 按字节读
//scanner.Split(bufio.ScanRunes) // 按 UTF-8 编码的字符读,如:中文字符

for scanner.Scan() {
	println(scanner.Text())
}
  1. 按指定字节长度读取
    可以使用 bufio.ReaderRead 方法,能读取指定长度的字节到一个切片中
go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	file, err := os.Open("filename.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	reader := bufio.NewReader(file)
	buf := make([]byte, 2)  // 指定读取的字节长度

	n, err := reader.Read(buf)
	if err != nil {
		return
	}

	fmt.Printf("读取的字节数: %d\n", n)
	fmt.Printf("读取的内容: %s\n", buf[:n])
}

假如要读取的文件中只有内容hello,那么将输出:

读取的字节数: 2
读取的内容: he

然后在此基础上,使用循环来读整个文件

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	file, err := os.Open("filename.txt")
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	reader := bufio.NewReader(file)
	buf := make([]byte, 2) // 指定读取的字节长度

	for {
		n, err := reader.Read(buf)
		if err != nil {
			break
		}
		fmt.Printf("%s\n", buf[:n])
	}
}

其输出将变为:

he
ll
o

写入

  1. 权限表示
    在 Unix 和类 Unix 系统的权限表示中,用3个数字表示,三个数字各代表了不同用户类别的访问权限:
  • 第一个数字:代表文件拥有者(owner)的权限。
  • 第二个数字:代表与文件拥有者同组的用户(group)的权限。
  • 第三个数字:代表其他所有用户(others)的权限。

每个数字可以是0到7之间的任意数字,分别控制读(4)、写(2)和执行(1)权限的开启和关闭。这些数字是对应的权限值的总和

  • 0 没有权限
  • 1 执行权限
  • 2 写权限
  • 4 读权限

一个权限表示是:0666,那么它其实是代表可读可写,前面的 0 是用来明确表示这是一个八进制数

  1. 操作标志
go 复制代码
// Flags to OpenFile wrapping those of the underlying system. Not all
// flags may be implemented on a given system.
const (
	// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
	O_RDONLY int = syscall.O_RDONLY // open the file read-only.
	O_WRONLY int = syscall.O_WRONLY // open the file write-only.
	O_RDWR   int = syscall.O_RDWR   // open the file read-write.
	// The remaining values may be or'ed in to control behavior.
	O_APPEND int = syscall.O_APPEND // append data to the file when writing.
	O_CREATE int = syscall.O_CREAT  // create a new file if none exists.
	O_EXCL   int = syscall.O_EXCL   // used with O_CREATE, file must not exist.
	O_SYNC   int = syscall.O_SYNC   // open for synchronous I/O.
	O_TRUNC  int = syscall.O_TRUNC  // truncate regular writable file when opened.
)

举几个例子:

go 复制代码
os.O_CREATE|os.O_WRONLY  // 不存在则创建,若存在则从头写入并覆盖原位置的内容,比如原先是hello,然后写入的是demo,那么会变成demoo
os.O_CREATE|os.O_TRUNC|os.O_WRONLY  // 不存在则创建,存在则清空
os.O_APPEND|os.O_WRONLY  // 追加写

常用方法:

go 复制代码
os.OpenFile(name string, flag int, perm FileMode) (*File, error)
os.WriteFile(name string, data []byte, perm FileMode) error  // 存在则清空后以原权限写入,不存在则以指定权限创建
os.Open(name string) (*File, error)  //模式为 O_RDONLY
os.Create(name string) (*File, error)  //Create 创建或清空,模式为 O_RDWR
os.Remove(name string) error  //将指定的文件或目录删除
os.RemoveAll(path string) error  //删除路径及其包含的任何子项

文件复制

go 复制代码
io.Copy(dst Writer, src Reader) (written int64, err error)
go 复制代码
package main

import (
	"io"
	"os"
)

// CopyFile copies a file from src to dst. If src and dst files exist, and are the same, then return error.
// If dst does not exist, it is created with mode 0666 (before umask).
func CopyFile(src, dst string) error {
	in, err := os.Open(src)
	if err != nil {
		return err
	}
	defer in.Close()

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()

	_, err = io.Copy(out, in)
	if err != nil {
		return err
	}

	return out.Sync()
}

func main() {
	src := "source.txt"
	dst := "destination.txt"
	if err := CopyFile(src, dst); err != nil {
		panic(err)
	}
}

操作目录

  1. 创建目录
go 复制代码
package main

import (
	"fmt"
	"os"
)

func main() {
	// 创建一个目录
	err := os.Mkdir("example_dir", 0755)
	if err != nil {
		fmt.Println(err)
	}

	// 创建目录路径中所有不存在的目录
	err = os.MkdirAll("example_dir/subdir", 0755)
	if err != nil {
		fmt.Println(err)
	}
}
  1. 读取目录
go 复制代码
os.ReadDir(name string) ([]DirEntry, error)  // go 1.16 引入

读取指定目录下的文件和文件夹,及其大小

go 复制代码
package main

import (
	"fmt"
	"os"
)

// convertSize 将字节大小转换为更可读的单位
func convertSize(size int64) string {
	const (
		KB = 1 << 10 // 1024
		MB = 1 << 20 // 1024 * 1024
		GB = 1 << 30 // 1024 * 1024 * 1024
	)

	switch {
	case size >= GB:
		return fmt.Sprintf("%.2f GB", float64(size)/GB)
	case size >= MB:
		return fmt.Sprintf("%.2f MB", float64(size)/MB)
	case size >= KB:
		return fmt.Sprintf("%.2f KB", float64(size)/KB)
	default:
		return fmt.Sprintf("%d B", size)
	}
}

func main() {
	entries, err := os.ReadDir(".") // 读取当前目录
	if err != nil {
		fmt.Println(err)
		return
	}

	for _, entry := range entries {
		info, err := entry.Info()
		if err != nil {
			// 如果无法获取文件信息,则跳过该文件
			fmt.Println("Error:", err)
			continue
		}
		fmt.Printf("%s: %s\n", info.Name(), convertSize(info.Size()))
	}
}

如果想读取子目录中的内容,可以添加一个循环,然后判断是否是目录,然后同样取即可,直至没有子目录

或者使用更高效的filepath.WalkDir(go 1.16),是filepath.Walk(go 1.0)的优化版,性能更好

go 复制代码
package main

import (
	"fmt"
	"os"
	"path/filepath"
)

// convertSize 将字节大小转换为更可读的单位
func convertSize(size int64) string {
	const (
		KB = 1 << 10 // 1024
		MB = 1 << 20 // 1024 * 1024
		GB = 1 << 30 // 1024 * 1024 * 1024
	)

	switch {
	case size >= GB:
		return fmt.Sprintf("%.2f GB", float64(size)/GB)
	case size >= MB:
		return fmt.Sprintf("%.2f MB", float64(size)/MB)
	case size >= KB:
		return fmt.Sprintf("%.2f KB", float64(size)/KB)
	default:
		return fmt.Sprintf("%d B", size)
	}
}

func visitFile(path string, d os.DirEntry, err error) error {
	if err != nil {
		fmt.Printf("访问文件时遇到错误: %v\n", err)
		return nil // 返回nil继续遍历
	}
	if !d.IsDir() {
		info, err := d.Info()
		if err != nil {
			fmt.Printf("获取文件信息时遇到错误: %v\n", err)
			return nil
		}
		fmt.Printf("%s: %s\n", path, convertSize(info.Size()))
	}
	return nil
}

func main() {
	err := filepath.WalkDir(".", visitFile)
	if err != nil {
		fmt.Printf("遍历目录时遇到错误: %v\n", err)
	}
}
相关推荐
加油,旭杏2 小时前
【go语言】函数
开发语言·后端·golang
沈韶珺5 小时前
Elixir语言的安全开发
开发语言·后端·golang
加油,旭杏9 小时前
【go语言】grpc 快速入门
开发语言·后端·golang
沈韶珺11 小时前
Visual Basic语言的云计算
开发语言·后端·golang
沈韶珺11 小时前
Perl语言的函数实现
开发语言·后端·golang
慕璃嫣12 小时前
Haskell语言的多线程编程
开发语言·后端·golang
加油,旭杏1 天前
【go语言】接口
开发语言·后端·golang
清北_1 天前
万科000002
golang
兮动人1 天前
Golang 执行流程分析
开发语言·后端·golang·golang 执行流程分析