继续开始读写数据的学习,其实就是I/O流了估计是,这方面还是挺重要的。
Scanln
扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。Scanf
与其类似,除了 Scanf
的第一个参数用作格式字符串,用来决定如何读取。(感觉Go这方面类似C的scanf了)
package main
import "fmt"
func main() {
fmt.Println("please input:")
var firstName,lastName string
var n1,n2 string
fmt.Scanln(&firstName,&lastName)
fmt.Printf("Hello %s %s\n",firstName,lastName)
fmt.Scanf("%s,%s",&n1,&n2)
fmt.Printf("%s,%s\n",n1,n2)
}
/*
please input:
a1 a2
Hello a1 a2
a1,a2
a1,a2,
*/
也可以用bufio包来读取:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
inputReader := bufio.NewReader(os.Stdin)
fmt.Println("please input:")
input, err := inputReader.ReadString('\n')
if err != nil {
fmt.Printf("input error!")
return
}
fmt.Println(input)
data := []byte(input)
fmt.Println(data)//包括\n
}
ReadString 返回读取到的字符串,如果碰到错误则返回 nil。如果它一直读到文件结束,则返回读取到的字符串和 io.EOF。如果读取过程中没有碰到 delim 字符,将返回错误 err != nil。
逐行读取文件:
package main
import (
"bufio"
"fmt"
"io"
"os"
"reflect"
)
func main() {
inputFile,inputError := os.Open("1.txt")
if inputError!=nil {
fmt.Println("file error!")
return
}
fmt.Println(reflect.TypeOf(inputFile))
defer inputFile.Close()
inputReader := bufio.NewReader(inputFile)
for {
inputString,readerError := inputReader.ReadString('\n')
fmt.Println(inputString)
if readerError == io.EOF{
return
}
}
}
也可以利用io/ioutil
的ReadFile()
函数讲整个文件的内容读取到一个[]byte
中:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
inputFile := "1.txt"
buf,err := ioutil.ReadFile(inputFile)
if err!=nil{
fmt.Println("error")
panic(err.Error())
}
fmt.Print(string(buf))
}
带缓冲的读取:
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
inputFile,inputError := os.Open("1.txt")
if inputError != nil {
panic(inputError.Error())
}
defer inputFile.Close()
inputReader := bufio.NewReader(inputFile)
var buf []byte = make([]byte,1024)
for {
n,err := inputReader.Read(buf)
if err==io.EOF{
break
}
fmt.Print(string(buf[:n]))
}
}
package main
import (
"bufio"
"os"
)
func main() {
outputFile,_ := os.OpenFile("1.txt",os.O_WRONLY|os.O_CREATE, 0666)
defer outputFile.Close()
outputWriter := bufio.NewWriter(outputFile)
outString := "hello,world\nwwwwww"
outputWriter.WriteString(outString)
outputWriter.Flush()
}
os.OpenFile
的第二个参数是flag,有如下常用标志:
os.O_RDONLY
:只读os.O_WRONLY
:只写os.O_CREATE
:创建:如果指定文件不存在,就创建该文件。os.O_TRUNC
:截断:如果指定文件已存在,就将该文件的长度截为 0。
也可以不使用缓冲区,直接写入:
package main
import (
"os"
)
func main() {
outputFile,_ := os.OpenFile("1.txt",os.O_WRONLY|os.O_CREATE, 0666)
defer outputFile.Close()
outputFile.WriteString("hello,world")
}
练习:
package main
import (
"fmt"
"io/ioutil"
"os"
)
type Page struct {
Title string
Body []byte
}
func (page *Page) save(){
outputFile,_ := os.OpenFile(page.Title,os.O_WRONLY|os.O_CREATE, 0666)
defer outputFile.Close()
outputFile.Write(page.Body)
}
func (page *Page) load(){
page.Body,_ =ioutil.ReadFile(page.Title)
fmt.Print(string(page.Body))
}
func main() {
page := new(Page)
page.Title = "2.txt"
page.Body = []byte("hello!!!!")
page.save()
page.load()
}
利用io.Copy()
package main
import (
"io"
"os"
)
func main() {
CopyFile("3.txt","1.txt")
}
func CopyFile(dstName,srcName string)(written int64,err error){
src,err := os.Open(srcName)
defer src.Close()
dst,err := os.OpenFile(dstName,os.O_WRONLY|os.O_CREATE,0666)
defer dst.Close()
return io.Copy(dst,src)
}
defer
的使用:当打开目标文件时发生了错误,那么 defer
仍然能够确保 src.Close()
执行。如果不这么做,文件会一直保持打开状态并占用资源。
os.Args
这个命令行参数会放置在切片 os.Args[]
中(以空格分隔),从索引 1 开始(os.Args[0]
放的是程序本身的名字)。
感觉比os包解析命令行参数更好,而且用法更偏向于那些命令行参数的解析。
每个Flag结构体:
type Flag struct {
Name string // name as it appears on command line
Usage string // help message
Value Value // value as set
DefValue string // default value (as text); for usage message
}
指定参数:
var do = flag.String("w","no out","print")
//func String(name string, value string, usage string) *string
注意返回的是指针。
flag.Parse() 扫描参数列表(或者常量列表)并设置 flag, flag.Arg(i) 表示第 i 个参数。Parse() 之后 flag.Arg(i) 全部可用,flag.Arg(0) 就是第一个真实的 flag,而不是像 os.Args(0) 放置程序的名字。
flag.Narg() 返回参数的数量。解析后 flag 或常量就可用了。
flag.PrintDefaults()
打印 flag 的使用帮助信息。
需要注意的是,从第一个不能解析的参数开始,后面的所有参数都是无法解析的。即使后面的参数中含有预定义的参数。
例子:
package main
import (
"flag"
"fmt"
)
var do = flag.String("w","no out","print")
func main() {
//flag.PrintDefaults()
flag.Parse() // Scans the arg list and sets up flags
fmt.Println(*do)
}
C:\Users\15997\Desktop>go run main.go -w 123
123
C:\Users\15997\Desktop>go run main.go
no out
C:\Users\15997\Desktop>go run main.go -w=123
123
C:\Users\15997\Desktop>
-help
可以起到flag.PrintDefaults()
的作用,不过它就只能打印帮助信息了,联想到之前使用工具中的-help,这部分还是挺重要的,接下来写工具就需要解析这些参数。
package main
import (
"fmt"
"os"
)
func cat(f *os.File){
const NBUF = 1024
var buf [NBUF]byte
for {
switch nr, _ := f.Read(buf[:]);true {
case nr<0:
fmt.Println("can not read")
os.Exit(1)
case nr==0://EOF
return
case nr>0:
fmt.Print(string(buf[:nr]))
}
}
}
func main() {
f,_ := os.Open("1.txt")
defer f.Close()
cat(f)
}
将对象转换为JSON:
package main
import (
"encoding/json"
"fmt"
"os"
)
type Person struct {
Age int
Name string
Mate School
}
type School struct{
Name string
Position string
}
func main(){
person := Person{18,"feng",School{"a","b"}}
//得到字符串
js,_ := json.Marshal(person)
fmt.Printf("%s",js)
//写入文件
f,_ := os.OpenFile("1.json",os.O_WRONLY|os.O_CREATE,0666)
defer f.Close()
enc := json.NewEncoder(f)
enc.Encode(person)
}
json.Marshal
注意结构体成员的首字母要大写才能成功转换。
出于安全考虑,在 web 应用中最好使用 json.MarshalforHTML()
函数,其对数据执行 HTML 转码,所以文本可以被安全地嵌在 HTML <script>
标签中。
不是所有的数据都可以编码为 JSON 类型:只有验证通过的数据结构才能被编码:
-
JSON 对象只支持字符串类型的 key;要编码一个 Go map 类型,map 必须是 map [string] T(T 是 json 包中支持的任何类型)
-
Channel,复杂类型和函数类型不能被编码
-
不支持循环数据结构;它将引起序列化进入一个无限循环
-
指针可以被编码,实际上是对指针指向的值进行编码(或者指针是 nil)
将JSON格式转换为对象:
package main
import (
"encoding/json"
"fmt"
)
type Person struct {
Age int
Name string
Mate School
}
type School struct{
Name string
Position string
}
func main(){
person := Person{18,"feng",School{"a","b"}}
//得到字符串
js,_ := json.Marshal(person)
fmt.Printf("%s\n",js)
var p Person
err := json.Unmarshal(js,&p)
if err!=nil{
panic(err.Error())
}
fmt.Println(p)
}
利用json.Unmarshal
:func Unmarshal(data []byte, v interface{}) error
第二个参数需要是指针。
Go也内置了许多的加密解密包。
-
hash 包:实现了 adler32、crc32、crc64 和 fnv 校验;
-
crypto 包:实现了其它的 hash 算法,比如 md4、md5、sha1 等。以及完整地实现了 aes、blowfish、rc4、rsa、xtea 等加密算法。
package main
import (
"crypto/md5"
"fmt"
"io"
)
func main(){
hasher := md5.New()
io.WriteString(hasher,"feng")
fmt.Printf("%x\n",hasher.Sum(nil))
//
hasher.Reset()
data := []byte("hello")
hasher.Write(data)
fmt.Printf("%x\n",hasher.Sum(nil))
fmt.Printf("%x",md5.Sum(data))
}