初识Go语言22-常用标准库【I/O操作】


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()即可

猜你喜欢

转载自blog.csdn.net/m0_52896752/article/details/129795980
今日推荐