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")