I/O操作
格式化输出
输出格式 | 输出内容 |
---|---|
%t | 单词 true 或 false |
%b | 表示为二进制 |
%d | 表示为十进制 |
%e | (=%.6e)有 6 位小数部分的科学计数法,如 -1234.456e+78 |
%f | (=%.6f)有 6 位小数部分,如 123.456123 |
%g | 根据实际情况采用 %e 或 %f 格式(获得更简洁、准确的输出) |
%s | 直接输出字符串或者字节数组 |
%v | 值的默认格式表示 |
%+v | 类似 %v,但输出结构体时会添加字段名 |
%#v | 值的 Go 语法表示 |
%Т | 值的类型的 Go 语法表示 |
标准输入
fmt.Println("please input two word")
var word1 string
var word2 string
fmt.Scan(&word1, &word2) //读入多个单词,空格分隔。如果输入了更多单词会被缓存起来,丢给下一次scan
fmt.Println("please input an int")
var i int
fmt.Scanf("%d", &i) //类似于Scan,转为特定格式的数据
输入输出的底层原理
- 终端其实是一个文件,相关实例如下:
os.Stdin
:标准输入的文件实例,类型为*File
os.Stdout
:标准输出的文件实例,类型为*File
os.Stderr
:标准错误输出的文件实例,类型为*File
以文件的方式操作终端:
package main
import "os"
func main() {
var buf [16]byte
os.Stdin.Read(buf[:])
os.Stdin.WriteString(string(buf[:]))
}
文件操作相关API
-
func Create(name string) (file *File, err Error)
- 根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666
-
func NewFile(fd uintptr, name string) *File
- 根据文件描述符创建相应的文件,返回一个文件对象
-
func Open(name string) (file *File, err Error)
- 只读方式打开一个名称为name的文件
-
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
- 打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限
-
func (file *File) Write(b []byte) (n int, err Error)
- 写入byte类型的信息到文件
-
func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
- 在指定位置开始写入byte类型的信息
-
func (file *File) WriteString(s string) (ret int, err Error)
- 写入string信息到文件
-
func (file *File) Read(b []byte) (n int, err Error)
- 读取数据到b中
-
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
- 从off开始读取数据到b中
-
func Remove(name string) Error
- 删除文件名为name的文件
打开和关闭文件
os.Open()
函数能够打开一个文件,返回一个*File
和一个err
。对得到的文件实例调用close()方法能够关闭文件。
package main
import (
"fmt"
"os"
)
func main() {
// 只读方式打开当前目录下的main.go文件
file, err := os.Open("./main.go")
if err != nil {
fmt.Println("open file failed!, err:", err)
return
}
// 关闭文件
file.Close()
}
打开文件
func os.Open(name string) (*os.File, error)
fout, err := os.OpenFile("data/verse.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
os.O_WRONLY以只写的方式打开文件,os.O_TRUNC把文件之前的内容先清空掉,os.O_CREATE如果文件不存在则先创建,0666新建文件的权限设置。
读文件
cont := make([]byte, 10)
fin.Read(cont) //读出len(cont)个字节,返回成功读取的字节数
fin.ReadAt(cont, int64(n)) //从指定的位置开始读len(cont)个字节
fin.Seek(int64(n), 0) //重新定位。whence: 0从文件开头计算偏移量,1从当前位置计算偏移量,2到文件末尾的偏移量
reader := bufio.NewReader(fin) //读文件文件建议用bufio.Reader
for { //无限循环
if line, err := reader.ReadString('\n'); err != nil { //指定分隔符
if err == io.EOF {
if len(line) > 0 { //如果最后一行没有换行符,则此时最后一行就存在line里
fmt.Println(line)
}
break //已读到文件末尾
} else {
fmt.Printf("read file failed: %v\n", err)
}
} else {
line = strings.TrimRight(line, "\n") //line里面是包含换行符的,需要去掉
fmt.Println(line)
}
}
写文件
package main
import (
"fmt"
"os"
)
func main() {
// 新建文件
file, err := os.Create("./xxx.txt")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
for i := 0; i < 5; i++ {
file.WriteString("ab\n")
file.Write([]byte("cd\n"))
}
}
写文件
defer fout.Close() //别忘了关闭文件句柄
writer := bufio.NewWriter(fout)
writer.WriteString("明月多情应笑我")
writer.WriteString("\n") //需要手动写入换行符
writer.Flush()// 强制清空缓存,即把缓存里的内容写入磁盘
读文件
文件读取可以用file.Read()和file.ReadAt(),读到文件末尾会返回io.EOF的错误
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件
file, err := os.Open("./xxx.txt")
if err != nil {
fmt.Println("open file err :", err)
return
}
defer file.Close()
// 定义接收文件读取的字节数组
var buf [128]byte
var content []byte
for {
n, err := file.Read(buf[:])
if err == io.EOF {
// 读取结束
break
}
if err != nil {
fmt.Println("read file err ", err)
return
}
content = append(content, buf[:n]...)
}
fmt.Println(string(content))
}
拷贝文件
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开源文件
srcFile, err := os.Open("./xxx.txt")
if err != nil {
fmt.Println(err)
return
}
// 创建新文件
dstFile, err2 := os.Create("./abc2.txt")
if err2 != nil {
fmt.Println(err2)
return
}
// 缓冲读取
buf := make([]byte, 1024)
for {
// 从源文件读数据
n, err := srcFile.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕")
break
}
if err != nil {
fmt.Println(err)
break
}
//写出去
dstFile.Write(buf[:n])
}
srcFile.Close()
dstFile.Close()
}
bufio
- bufio包实现了带缓冲区的读写,是对文件读写的封装
- bufio缓冲写数据
模式 | 含义 |
---|---|
os.O_WRONLY | 只写 |
os.O_CREATE | 创建文件 |
os.O_RDONLY | 只读 |
os.O_RDWR | 读写 |
os.O_TRUNC | 清空 |
os.O_APPEND | 追加 |
- bufio读数据
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func wr() {
// 参数2:打开模式,所有模式d都在上面
// 参数3是权限控制
// w写 r读 x执行 w 2 r 4 x 1
file, err := os.OpenFile("./xxx.txt", os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
return
}
defer file.Close()
// 获取writer对象
writer := bufio.NewWriter(file)
for i := 0; i < 10; i++ {
writer.WriteString("hello\n")
}
// 刷新缓冲区,强制写出
writer.Flush()
}
func re() {
file, err := os.Open("./xxx.txt")
if err != nil {
return
}
defer file.Close()
reader := bufio.NewReader(file)
for {
line, _, err := reader.ReadLine()
if err == io.EOF {
break
}
if err != nil {
return
}
fmt.Println(string(line))
}
}
func main() {
re()
}
ioutil工具包
- 工具包写文件
- 工具包读取文件
package main
import (
"fmt"
"io/ioutil"
)
func wr() {
err := ioutil.WriteFile("./yyy.txt", []byte("www.5lmh.com"), 0666)
if err != nil {
fmt.Println(err)
return
}
}
func re() {
content, err := ioutil.ReadFile("./yyy.txt")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(content))
}
func main() {
re()
}
例子
实现一个cat命令
使用文件操作相关知识,模拟实现linux平台cat命令的功能。
package main
import (
"bufio"
"flag"
"fmt"
"io"
"os"
)
// cat命令实现
func cat(r *bufio.Reader) {
for {
buf, err := r.ReadBytes('\n') //注意是字符
if err == io.EOF {
break
}
fmt.Fprintf(os.Stdout, "%s", buf)
}
}
func main() {
flag.Parse() // 解析命令行参数
if flag.NArg() == 0 {
// 如果没有参数默认从标准输入读取内容
cat(bufio.NewReader(os.Stdin))
}
// 依次读取每个指定文件的内容并打印到终端
for i := 0; i < flag.NArg(); i++ {
f, err := os.Open(flag.Arg(i))
if err != nil {
fmt.Fprintf(os.Stdout, "reading from %s failed, err:%v\n", flag.Arg(i), err)
continue
}
cat(bufio.NewReader(f))
}
}
创建文件/目录
os.Create(name string)//创建文件
os.Mkdir(name string, perm fs.FileMode)//创建目录
os.MkdirAll(path string, perm fs.FileMode)//增强版Mkdir,沿途的目录不存在时会一并创建
os.Rename(oldpath string, newpath string)//给文件或目录重命名,还可以实现move的功能
os.Remove(name string)//删除文件或目录,目录不为空时才能删除成功
os.RemoveAll(path string)//增强版Remove,所有子目录会递归删除
遍历目录
if fileInfos, err := ioutil.ReadDir(path); err != nil {//fileInfos是切片
return err
} else {
for _, fileInfo := range fileInfos {
fmt.Println(fileInfo.Name())
if fileInfo.IsDir() { //如果是目录,就递归子遍历
walk(filepath.Join(path, fileInfo.Name}
}
}
默认的log输出到控制台。
log.Printf("%d+%d=%d\n", 3, 4, 3+4)
log.Println("Hello Golang")
log.Fatalln("Bye, the world") //日志输出后会执行os.Exit(1)
指定日志输出到文件。
logWriter := log.New(fout, "[BIZ_PREFIX]", log.Ldate|log.Lmicroseconds) //通过flag参数定义日志的格式,fout创建的文件,[BIZ_PREFIX]给一个日志前面的固定格式
logWriter.Println("Hello Golang")
调用系统命令
cmd_path, err := exec.LookPath("df") //查看系统命令所在的目录,确保命令已安装
cmd := exec.Command("df", "-h") //相当于命令df -h,注意Command的每一个参数都不能包含空格
output, err := cmd.Output() //cmd.Output()运行命令并获得其输出结果
cmd = exec.Command("rm", "./data/test.log")
cmd.Run() //如果不需要获得命令的输出,直接调用cmd.Run()即可