15 文件操作与终端读取
主要涉及的模块
- os
- bufio
- ioutil
终端读取
终端读取我们可以使用os模块,分别是:
- os.Stdin 标准输入
- os.Stdout 标准输出
- os.Stderr 标准错误输出
终端读例子:
fmt不带缓冲区 的读。
读取的话可以使用最简单的fmt模块。代码如下所示:
package main
import (
"fmt"
)
var (
firstName, lastName, s string
i int
f float32
input = "56.12 / 5212 / Go"
format = "%f / %d / %s"
)
func main() {
fmt.Println("Please enter your full name: ")
fmt.Scanln(&firstName, &lastName) // 从终端读取
// fmt.Scanf("%s %s", &firstName, &lastName)
fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi Chris Naegels
fmt.Sscanf(input, format, &f, &i, &s) //从终端读取,且能够被格式化成其他数据类型
fmt.Println("From the string we read: ", f, i, s)
}
bufio带缓冲区的读
带缓冲区的读的话,可以减少IO的压力。
package main
import (
"bufio"
"fmt"
"os"
)
var inputReader *bufio.Reader
var input string
var err error
func main() {
inputReader = bufio.NewReader(os.Stdin)
fmt.Println("Please enter some input: ")
input, err = inputReader.ReadString('\n') // 也可以ReadLine
if err == nil {
fmt.Printf("The input was: %s\n", input)
}
}
练手的例子:从终端读取一行字符串,统计英文、数字、空格以及其他字符的数量
如何统计英文数字以及空格呢?我们可以使用ascii码的大小来比较统计,我们for循环出来的都是一个一个的字符byte,所以可以很容易的找到这个ascii,比如判断字符 a<b,go会自动转为ascii码来对比,由于b比a的ascii码更大,所以是正确的。了解原因后,我们看看下面的代码,
代码如下:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var azNum int
var intNum int
var fuhaoNum int
var otherNum int
rawstring, _, _ := reader.ReadLine()
result := []rune(string(rawstring))
for _, key := range result {
//fmt.Printf("%v %T\n", key, key)
switch {
case key >= 'a' && key <= 'z':
fallthrough
case key >= 'A' && key <= 'Z':
azNum++
case key >= '0' && key <= '9':
intNum++
case key == ' ' || key == '\t':
fuhaoNum++
default:
otherNum++
}
}
fmt.Println("azNum", azNum)
fmt.Println("intNum", intNum)
fmt.Println("fuhaoNum", fuhaoNum)
fmt.Println("otherNum", otherNum)
}
文件的读写
os.File封装所有文件相关操作,之前讲的 os.Stdin,os.Stdout, os.Stderr都是*os.File
- 打开一个文件进行读操作: os.Open(name string) (*File, error)
- 关闭一个文件:File.Close()
文件的读
我们接下来看看文件操作的示例,文件打开的话我们使用os.Open方法来打开
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
inputFile, err := os.Open("aaa.go") // 打开一个文件
if err != nil {
fmt.Printf("open file err:%v\n", err)
return
}
defer inputFile.Close()
inputReader := bufio.NewReader(inputFile)
for {
inputString, readerError := inputReader.ReadString('\n')
if readerError == io.EOF {
return
}
fmt.Printf("The input was: %s", inputString)
}
}
文件的写(ioutil.WriteFile)
文件写入我们可以使用os.OpenFile(),也可以使用ioutil.WriteFile()
- ioutil.ReadFile和ioutil.WriteFile 是整读整取。
代码如下:
// readFile_ioutil
package main
import (
"fmt"
"io/ioutil"
"os"
)
func main() {
inputFile := "d:/111.txt"
outputFile := "d:/112.txt"
buf, err := ioutil.ReadFile(inputFile)
if err != nil {
fmt.Fprintf(os.Stderr, "File error:%s", err)
}
fmt.Printf("%s\n", string(buf))
err = ioutil.WriteFile(outputFile, buf, 0644)
if err != nil {
panic(err.Error())
}
}
文件的写(bufio.NewWriter与os.OpenFile)
- 代码:os.OpenFile(“output.dat”, os.O_WRONLY|os.O_CREATE, 0666)
- 第二个参数:文件打开模式:
- os.O_WRONLY:只写
- os.O_CREATE:创建文件
- os.O_RDONLY:只读
- os.O_RDWR:读写
- os.O_TRUNC :清空
- 第三个参数:权限控制:
- r ——> 004
- w——> 002
- x——> 001
我们使用os.OpenFile来打开一个文件,os.O_WRONLY|os.O_CREATE 表示是如果没有那么就创建新文件,只读写该文件,权限模式为0666,
完整代码如下:
// WriteToFile
package main
import (
"bufio"
"os"
"fmt"
)
func main() {
outputFile,err := os.OpenFile("output.txt",os.O_WRONLY|os.O_CREATE,0666)
if err != nil {
fmt.Printf("an error happend with fil crea\n")
return
}
defer outputFile.Close()
outputWriter := bufio.NewWriter(outputFile)
outputString := "hello world!\n"
for i:=0;i<10;i++ {
outputWriter.WriteString(outputString)
}
outputFile.Flush()
}
利用读写来拷贝文件
我们这次实现拷贝文件通过边读边写的方式来实现文件的拷贝,主要是使用os.OpenFile和os.Open来时实现,代码如下:
// copyFile
package main
import (
"fmt"
"io"
"os"
)
func copyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
fmt.Println("happend a error when opening", err)
}
defer src.Close()
dst, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
fmt.Println("happend a error when opening", err)
}
defer dst.Close()
return io.Copy(dst, src)
}
func main() {
copyFile("test.gz", "test.log.gz")
}