Golang——IO操作

1. 输入输出的底层原理

终端其实是一个文件(Linux下一切皆文件),相关实例如下:

  • os.Stdin:标准输出的文件实例,类型为*File
  • os.Stdout:标准输入的文件实例,类型为*File
  • os.Stderr:标准错误输出的文件实例,类型为*File

以文件方式操作终端:

Go 复制代码
package main

import (
	"os"
)

func main() {
	var buf []byte
	os.Stdin.Read(buf[:])             //从标准输入中读取
	os.Stdin.WriteString(string(buf)) //写入标准输入
}

2. 文件操作相关API

根据提供的文件名创建新的文件,返回一个文件对象,默认权限0666,任何人可读可写,不可执行,如果文件存在,则会截断它(为空文件),如果成功,返回的文件对象可用于I/O;对应的文件描述符具有O_RDWR模式。如果出错,错误底层类型是*PathError。

Go 复制代码
func Create(name string) (file *File, err error)

NewFile使用给出的Unix文件描述符和名称创建一个文件。

Go 复制代码
func NewFile(fd uintptr, name string) *File

只读方式打开一个名称为name文件。

Go 复制代码
func Open(name string) (file *File, err error)

打开一个名为name的文件,flag是打开方式,只读或只写,不存在创建等,perm文件权限。

Go 复制代码
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)

在指定位置(相对于文件起始位置),写入byte类型的数据到文件,它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

Go 复制代码
func (f *File) WriteAt(b []byte, off int64) (n int, err error)

向文件中写入string类型的信息到文件。

Go 复制代码
func (f *File) WriteString(s string) (ret int, err error)

从f中读取最多len(b)字节数的数据到b。

Go 复制代码
func (f *File) Read(b []byte) (n int, err error)

从f的指定位置(相对于文件起始位置),读取len(b)字节数并写入b。

Go 复制代码
func (f *File) ReadAt(b []byte, off int64) (n int, err error)

删除name指定的文件或目录。

Go 复制代码
func Remove(name string) error

3. 打开和关闭文件

os.Open()函数能够打开一个文件,返回一个*File和一个err。对得到的文件实例调用close()方法能够关闭文件。

Go 复制代码
package main

import (
	"log"
	"os"
)

func main() {
	//只读的方式打开文件
	f, err := os.Open("./main.go")
	if err != nil {
		log.Println("open main.go file fail")
		return
	}
	//关闭文件
	defer f.Close()
}

4. 写文件

Go 复制代码
package main

import (
	"log"
	"os"
)

func main() {
	//可读可写的方式创建一个文件
	f, err := os.Create("./xx.txt")
	if err != nil {
		log.Println("create file fail")
		return
	}
	defer f.Close()

	for i := 0; i < 5; i++ {
		f.Write([]byte("ab\n"))
		f.WriteString("ab\n")
	}
}

5. 读文件

文件读取可以用file.Read()和file.ReadAt(),读到文件末尾会返回io.EOF的错误。

Go 复制代码
package main

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

func main() {
	f, err := os.Open("./xx.txt")
	if err != nil {
		log.Println("open file fail")
		return
	}
	defer f.Close()

	var content []byte
	for {
		var buf [128]byte
		n, err := f.Read(buf[:])
		if err == io.EOF {
			//读到文件末尾
			break
		}
		if err != nil {
			log.Println("Read file fail", err)
			return
		}
		content = append(content, buf[:n]...) //buf[:n]切片被打散传入
	}
	fmt.Println(string(content))
}

**"..."的用法:**三个点"..."其实是go的一种语法糖(糖衣语法)

● 第一个用法主要是用于函数有多个不定参数的情况,表示为可变参数,可以接受任意个数但相同类型的参数。

● 第二个用法是slice可以被打散进行传递。

6. 拷贝文件

Go 复制代码
package main

import (
	"io"
	"log"
	"os"
)

func main() {
	f1, err := os.Open("./xx.txt")
	if err != nil {
		log.Println("open xx.txt file fail", err)
		return
	}
	defer f1.Close()
	f2, err := os.Create("./abc.txt")
	if err != nil {
		log.Println("create file fail ", err)
		return
	}
	defer f2.Close()

	for {
		var buf [128]byte
		n, err := f1.Read(buf[:])
		if err == io.EOF {
			log.Println("读取完毕")
			break
		}
		if err != nil {
			return
		}

		f2.Write(buf[:n])
	}
}

7. bufio

  • bufio包实现了带缓冲区的读写,是对文件读写的封装。
  • bufio缓冲写数据。
  • bufio读数据 ,bufio先把数据读/写到缓冲区,达到某一上限,会刷新到文件中,也可以强制刷新。
Go 复制代码
package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
)

func wr() {
	f, err := os.OpenFile("./xxx.txt", os.O_CREATE|os.O_WRONLY, 0664)
	if err != nil {
		log.Println("open file fail ", err)
		return
	}
	defer f.Close()
    //获取writer对象
	writer := bufio.NewWriter(f)
	for i := 0; i < 5; i++ {
		writer.WriteString("hello\n")
	}
	//刷新缓冲区,强制写入
	writer.Flush()
}

func rd() {
	f, err := os.Open("./xxx.txt")
	if err != nil {
		log.Println("open file fail")
		return
	}
	defer f.Close()

    //获取reader对象
	reader := bufio.NewReader(f)
	var content []byte
	for {
		line, _, err := reader.ReadLine()
		if err == io.EOF {
			log.Println("读取完毕")
			break
		}
		if err != nil {
			return
		}
		content = append(content, line...)
	}
	fmt.Println(string(content))
}

func main() {
	wr()
	rd()
}

8. ioutil工具包

  • 工具包写文件
  • 工具包读文件
Go 复制代码
package main

import (
	"fmt"
	"io/ioutil"
	"log"
)

func wr() {
	err := ioutil.WriteFile("./xxxx.txt", []byte("hello world!"), 0666)
	if err != nil {
		log.Println("err")
		return
	}
}

func rd() {
	data, err := ioutil.ReadFile("./xxxx.txt")
	if err != nil {
		log.Println("err")
		return
	}
	fmt.Println(string(data))
}

func main() {
	wr()
	rd()
}

9. 例子

实现cat命令

Go 复制代码
package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
)

func cat(reader *bufio.Reader) {
	for {
		buf, err := reader.ReadBytes('\n') //注意是字符
		if err == io.EOF {
			break
		}
		fmt.Fprintf(os.Stdout, "%s", string(buf))
	}
}

func main() {
	flag.Parse()
	if flag.NArg() == 0 {
		cat(bufio.NewReader(os.Stdin))
	} else {
		for i := 0; i < flag.NArg(); i++ {
			f, err := os.Open(flag.Arg(i))
			if err != nil {
				log.Printf("open file %s fail, err %v\n", flag.Arg(i), err)
				continue
			}
			cat(bufio.NewReader(f))
			f.Close()
		}
	}
}
相关推荐
__AtYou__1 小时前
Golang | Leetcode Golang题解之第417题太平洋大西洋水流问题
leetcode·golang·题解
拉玛干1 小时前
社团周报系统可行性研究-web后端框架对比-springboot,django,gin
数据库·python·spring·golang
gopher95113 小时前
go语言 数组和切片
开发语言·golang
gopher95113 小时前
go语言Map详解
开发语言·golang
Python私教3 小时前
Go语言现代web开发15 Mutex 互斥锁
开发语言·前端·golang
java知路8 小时前
go 以太坊代币查余额
golang
gopher95118 小时前
go语言基础入门(一)
开发语言·golang
大得36910 小时前
go注册中心Eureka,注册到线上和线下,都可以访问
开发语言·eureka·golang
王中阳Go15 小时前
字节跳动的微服务独家面经
微服务·面试·golang
qq_1728055920 小时前
GO GIN 推荐的库
开发语言·golang·gin