平常使用的输入输出操作:
func main() {
fmt.Println("输入输出测试")
var a int
var b string
fmt.Scanln(&a, &b) // 从终端读取字符串(输入时以空格分隔)
fmt.Scanf("%d %s", &a, &b) // 格式化从终端读取(输入时以空格分隔)
fmt.Println(a) // 向终端打印
fmt.Printf("a=%d, b=%s", a, b) // 格式化向终端打印
}
其实, fmt.Fprintf()才是标准输出设备向控制台写数据的标准函数
如上的fmt.Printf(data)封装了fmt.Fprintf(io.Writer, data)
所以标准写法是: fmt.Fprinf(os.Stdout, data) -- os.Stdout表示控制台, 属于io.Writer类型
fmt.Fprintf()当然可以用于向文件写数据, 只需要修改os.Stdout 为*os.File类型的变量即可
func main() {
// 创建一个文件变量
file, err := os.OpenFile("c:/a.log", os.O_CREATE|os.O_WRONLY, 0)
if err != nil {
fmt.Println("打开文件失败")
return
}
fmt.Fprintf(file, "abc123222") // 向file对应文件中写入数据
file.Close()
fmt.Fprintf(os.Stdout, "abc123222") // 向控制台(标准输出设备)输出数据
}
注: os.File封装所有文件相关的操作, 如下操作终端相关的常量都是 *os.File
os.stdin 标准输入
os.stdout 标准输出
os.stderr 标准错误输出
与fmt.Fprintf()对应的是fmt.Fscanf()
func main() {
var s string
fmt.Fscanf(os.Stdin, "%s", &s) // 根据空格读取
fmt.Println(s)
file, err := os.Open("c:/b.log")
if err != nil {
panic(err)
}
var a, b, c, d string
fmt.Fscanf(file, "%s", &a)
fmt.Fscanf(file, "%s", &b) // 根据空格分开读取
fmt.Fscanf(file, "%s", &c)
fmt.Fscanf(file, "%s", &d )
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
fmt.Println(d)
}
另外, fmt.Sscanf(...) 函数可以从 字符串 中读取数据(相当于分解字符串, 比split强大)
第二个参数格式化目标字符串, 而split局限于单一分隔符
func main() {
var (
a, b int
str, c string
)
str = "10 20,abc"
fmt.Sscanf(str, "%d %d,%s", &a, &b, &c) // 第一个是目标字符串, 第二个是格式化, 第三个是赋值
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
最基础的读操作:
func main() {
file, err := os.Open("c:/a.log") // 读操作一般使用Open打开文件
if err != nil {
// 文件打开失败
return
}
defer file.Close() // 关文件
var b []byte = make([]byte, 2*1024) // 创建字节切片, 大小自己定
byts , err := file.Read(b) // 向file的文件中读取b大小的字节
fmt.Println(byts)
}
最基础的写操作:
func main() {
file, err := os.OpenFile("c:/b.log", os.O_CREATE|os.O_WRONLY, 0644) // 写操作只能使用OpenFile打开文件
if err != nil {
// 文件打开失败
return
}
defer file.Close()
str := "my name is 张三, i am in China"
var b = []byte(str)
byts , err := file.Write(b) // 将b大小的字节写入file的文件
fmt.Println(byts)
}
带缓冲区的向文件写入数据:
它有三个参数, 第一个参数表示目标文件, 第二个参数写入方式, 第三个是权限
使用NewWriter创建*Writer, 再用WriterString写入文件
由于操作的是缓存区, 所以写入文件时, 需要Flush一下, 否则写入不成功
func main() {
file, err := os.OpenFile("c:/a.log", os.O_CREATE|os.O_APPEND , 0666)
defer file.Close()
if err != nil {
fmt.Println("打开文件失败", err)
}
writer := bufio.NewWriter(file)
num, err2 := writer.WriteString("123")
writer.Flush() // 一定要使用flush, 否则很可能不能成功写入硬盘
if err2 != nil {
fmt.Println("文件写入失败", err2)
}
fmt.Println("写入字节数:", num)
}
带缓冲的读取文件
如果直接操作硬盘, 显然速度很慢
使用缓冲区, 则是先操作内存缓冲区, 后面才将数据刷到硬盘(不是直接操作硬盘), 这样可以大大提高效率
func main() {
var reader *bufio.Reader = bufio.NewReader(os.Stdin)
str, err := reader.ReadString('a') // 需要的参数为一个字节, 表示以这个字节结束
if err!= nil {
fmt.Println("fail")
return
}
fmt.Printf(str)
}
如果要读取一行, 则参数改为使用 '\n'
从文件读一行数据:
func main() {
file, err := os.Open("c:/a.log")
if err != nil {
fmt.Println("打开文件失败", err)
return
}
defer file.Close() // 关文件, 只需要关原始的这个文件就行了
var reader = bufio.NewReader(file)
str, err2 := reader.ReadString('\n') // 表示以换行符结束
if err != nil {
fmt.Println("读取文件失败", err2)
return
}
fmt.Printf(str)
}
例: 统计一个文件中的所有大小写字母数量, 数字, 空格, 其它字符
package main
import (
"fmt"
"os"
"bufio"
"io"
)
/*抽象一个结构体, 用于表示 字母 数字 空格 其它字符*/
type Count struct {
zimu int
number int
space int
other int
}
func main() {
file, err := os.Open("c:/a.log") // 打开文件
if err != nil {
fmt.Println("打开文件失败", err)
return
}
defer file.Close() // 关闭文件
var reader = bufio.NewReader(file) // 创建 *Reader
var count *Count = &Count{}
for {
str, err2 := reader.ReadString('\n') // 以行结尾
if err2 == io.EOF { // 读取到最后, 用io.EOF来判断
fmt.Println("读取文件完成")
break
}
if err2 != nil {
fmt.Println("读取文件失败", err2)
break
}
/*将str 转换为rune切片*/
array:= []rune(str)
for _, v := range array {
switch {
case v >='a' && v <='z':
fallthrough
case v >='A' && v<='Z':
count.zimu ++
case v >= '0' && v <='9':
count.number ++
case v == ' ' || v=='\t':
count.space ++
default:
count.other ++
}
}
}
fmt.Println(*count)
}
读取压缩文件:
先打开压缩文件, 再根据压缩文件创建创建Reader
再使用bufio创建Reader, 这样就可以读取了
func main() {
gfile, err := os.Open("c:/a.log.gz") // 打开压缩文件
defer gfile.Close()
if err != nil {
fmt.Println("打开文件失败", err)
return
}
greader, err := gzip.NewReader(gfile) // 根据压缩文件, 创建greader
var breader = bufio.NewReader(greader) // 根据greader构建breader
for {
str, err2 := breader.ReadString('\n') // 以行结尾
if err2 == io.EOF {
fmt.Println("读取文件结束")
break
}
fmt.Println(str)
}
}
文件拷贝:
io.Copy(dest, source) -- 传入两个参数Writer, Reader
func main() {
sourcefile, err := os.Open("c:/a.log")
if err != nil {
// 文件打开失败
return
}
defer sourcefile.Close()
destfile, err2 := os.OpenFile("c:/b.log", os.O_CREATE|os.O_WRONLY, 0644)
if err2 != nil {
// 文件打开失败
return
}
defer destfile.Close()
io.Copy(destfile, sourcefile)
}