12.1 读取用户的输入
在程序中,程序读取的用户输入口,都是在控制台,即标准输入os.stdin。
可以使用flag包。
func main() {
s := flag.String("n", "吴彦祖", "-n=吴彦祖") //n参数,默认吴彦祖,用法-n=吴彦祖
i := flag.Int("i", 1, "-i=1") //i参数,默认1,用法-i=1
flag.Parse() //flag实例
fmt.Println(*s, *i) //吴彦祖 9
}
也可以做参数绑定。
package main
import (
"flag"
"fmt"
)
var (
name string //姓名
age int //年龄
height float64 //身高
)
func main() {
flag.StringVar(&name, "n", "吴彦祖", "-n=吴彦祖") //n参数,默认吴彦祖,用法-n=吴彦祖
flag.IntVar(&age, "i", 1, "-i=1") //i参数,默认1,用法-i=1
flag.Float64Var(&height, "h", 1.8, "-h=1.8") //h参数,默认1.8,用法-h=1.8
flag.Parse() //flag实例
fmt.Println("姓名", name)
fmt.Println("年龄", age)
fmt.Println("身高", height)
}
12.2 文件操作
12.2.1 读
文件的读取可以使用os.Open打开文件句柄,然后用bufio包进行字节或字符串读取。
package main
import (
"bufio"
"fmt"
"io"
"os"
)
func main() {
f, err := os.Open("dir.txt") //返回文件句柄
if err != nil {
fmt.Println("文件读取失败", err)
return
}
defer f.Close() //函数调用完就关闭文件句柄
file := bufio.NewReader(f) //返回一个读取器
for {
s, err := file.ReadString('\n') //按行读,行结束符是\n
if err == io.EOF { //文件读取结束
return
}
fmt.Println(s)
}
}
如果是想把整个文件都读入一个字符串中,使用ioutil包。
package main
import (
"fmt"
"io/ioutil"
)
func main() {
file, err := ioutil.ReadFile("dir.txt")
if err != nil {
fmt.Println("文件读取失败")
return
}
fmt.Println(string(file))
}
如果想读取压缩文件,可以使用compress包,支持bzip2,flate,gzip,lze和zlib等。
package main
import (
"bufio"
"compress/gzip"
"fmt"
"io"
"os"
)
func main() {
f, err := os.Open("dir.7z")
if err != nil {
fmt.Println("文件读取失败")
return
}
defer f.Close()
fz, err := gzip.NewReader(f)
var r *bufio.Reader
if err != nil {
r = bufio.NewReader(f) //解压失败,可能不是压缩包,则按正常文件读取
} else {
r = bufio.NewReader(fz) //传入解压后的对象
}
for {
line, err := r.ReadString('\n')
if err == io.EOF {
fmt.Println("文件读取结束")
return
}
fmt.Println(line)
}
}
12.2.2 写
写文件先打开文件句柄os.OpenFile,然后使用bufio包写入。
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
f, err := os.OpenFile("dir.txt", os.O_WRONLY|os.O_CREATE, 0666) //只写,没有文件就创建,权限是0666
if err != nil {
fmt.Println("文件句柄打开失败")
}
defer f.Close()
owriter := bufio.NewWriter(f) //文件写入器
s := "吴彦祖"
for i := 0; i < 10; i++ {
owriter.WriteString(s) //写入器写入字符串,写入到开头
}
owriter.Flush() //刷新
}
12.2.3 复制
文件的拷贝可以使用io包的copy函数。
package main
import (
"fmt"
"io"
"os"
)
func main() {
srcf, err := os.Open("dir.txt")
if err != nil {
fmt.Println("dir.txt文件打开句柄失败")
return
}
defer srcf.Close() //后执行
dstf, err := os.Create("dir-2.txt") //不存在就创建,存在就覆盖
if err != nil {
fmt.Println("目标文件后创建失败")
return
}
defer dstf.Close() //先执行
io.Copy(dstf, srcf)
}
12.3 json数据
json,xml等数据结构在网络传输过程中,必须经过编码和解码,提高其可读性。
- 数据结构 —> 指定格式 = 序列化 或 编码(传输之前)
- 指定格式 —> 数据结构 = 反序列化 或 解码(传输之后)
12.3.1 序列化和反序列化
使用json包的Marsha1函数进行序列化成json数据。 ```go package main
import ( “encoding/json” “fmt” )
type person struct { Name string Age int Height float64 }
func main() { m := person{“吴彦祖”, 18, 1.80} //实例化Persion对象 j, _ := json.Marshal(m) //序列化 fmt.Println(string(j)) //{“Name”:”吴彦祖”,”Age”:18,”Height”:1.8}
m1 := new(person) //返回指针
json.Unmarshal(j, m1) //反序列化
fmt.Println(*m1) //打印值
}
要注意,结构体中的属性,首字母一定要**大写**,也就是一定要可导出。<br />要注意m1 := new(person),这里不能m1 := person{},因为反序列化时要使用**指针**,而不是实例。
<a name="NZ82x"></a>
### 12.3.2 保存到文件
可以以json的格式将数据保存到文件中,实现持久化。
```go
package main
import (
"encoding/json"
"os"
)
type person struct {
Name string
Age int
Height float64
}
func main() {
m := person{"吴彦祖", 18, 1.80} //实例化Persion对象
f, _ := os.OpenFile("data.json", os.O_CREATE|os.O_WRONLY, 0666) //打印文件句柄
defer f.Close() //防止忘记关闭句柄
enc := json.NewEncoder(f) //编码器
enc.Encode(m) //编码
}
从文件读json数据的话,就是返过来,解码。
package main
import (
"encoding/json"
"fmt"
"os"
)
type person struct {
Name string
Age int
Height float64
}
func main() {
m := new(person)
f, _ := os.Open("data.json") //打印文件句柄
defer f.Close() //防止忘记关闭句柄
enc := json.NewDecoder(f) //解码器
enc.Decode(m) //解码
fmt.Println(*m)
}
12.3.3 json支持的格式
并不是所有的数据类型都可以编码成json类型的:
- JSON 对象只支持字符串类型的 key;要编码一个 Go map 类型,map 必须是 map[string]T(T 是 json 包中支持的任何类型)
- Channel,复杂类型和函数类型不能被编码
- 不支持循环数据结构;它将引起序列化进入一个无限循环
- 指针可以被编码,实际上是对指针指向的值进行编码(或者指针是 nil)
12.4 xml数据
xml和json的做法几乎是一模一样的,就是把json包换成xml包即可。12.4.1 序列化和反序列化
```go package main
import ( “encoding/xml” “fmt” )
type person struct { Name string Age int Height float64 }
func main() {
m := person{“吴彦祖”, 18, 1.80}
x, _ := xml.Marshal(m)
fmt.Println(string(x)) //
m1 := new(person) //用来存放反序列化后的数据
xml.Unmarshal(x, m1) //反序列化
fmt.Println(*m1) //{吴彦祖 18 1.8}
}
<a name="q7dFB"></a>
## 12.5 Go中的密码学
网络数据传输过程中,敏感数据是必须要加密的,以防窃听盗取。<br />一些有关密码学的标准包:
- hash 包:实现了 adler32、crc32、crc64 和 fnv 校验;
- crypto 包:实现了其它的 hash 算法,比如 md4、md5、sha1 等。以及完整地实现了 aes、blowfish、rc4、rsa、xtea 等加密算法。
```go
//SHA1 例子
package main
import (
"crypto/sha1"
"fmt"
)
func main() {
s := "我是吴彦祖,我为自己带盐"
h := sha1.New() //hash对象
h.Write([]byte(s)) //写入
hashdata := h.Sum(nil) //sum用于追加
fmt.Printf("%x", hashdata) //d3210afa888854036e9fad0e989ae89900042623
}
MD5的计算和sha1是一样的,就是把sha1包换成MD5就行了。
package main
import (
"crypto/md5"
"fmt"
)
func main() {
s := "我是吴彦祖,我为自己带盐"
h := md5.New()
h.Write([]byte(s))
md5data := h.Sum(nil)
fmt.Printf("%x", md5data) //39a0a8f8d78ea57f3762a9e883d9d5d4
}