defer 与 panic
压栈 遇到panic出栈 后进先出,先进后出
package main
import "fmt"
func main() {
defer_func()
}
func defer_func() {
defer func() {
fmt.Println("1")
}()
defer func() {
fmt.Println("2")
}()
defer func() {
fmt.Println("3")
}()
panic("我是panic")
}
- 注意执行顺序,捕获到err 就执行panic 之后再打印1 panic后面不会被执行 没有panic不会被err捕获到 也会执行
package main
import "fmt"
func main() {
defer_func()
}
func defer_func() {
defer func() {
if err:=recover();err!=nil{
fmt.Printf("被recover捕获的panic 内容是:%v\n",err)
}
fmt.Println("1")
}()
defer func() {
fmt.Println("2")
}()
defer func() {
fmt.Println("3")
}()
panic("我是panic")
}
- 注释掉panic 会正常执行,顺序是 4321
package main
import "fmt"
func main() {
defer_func()
}
func defer_func() {
defer func() {
if err:=recover();err!=nil{
fmt.Printf("被recover捕获的panic 内容是:%v\n",err)
}
fmt.Println("1")
}()
defer func() {
fmt.Println("2")
}()
defer func() {
fmt.Println("3")
}()
//panic("我是panic")
fmt.Println("4")
}
- 压进栈的会倒序执行输出
func main() {
defer_func()
}
func defer_func() {
defer func() {
fmt.Println("2")
}()
defer func() {
fmt.Println("3")
}()
defer func() {
if err:=recover();err!=nil{
fmt.Printf("被recover捕获的panic 内容是:%v :%T\n",err,err)
}
fmt.Println("1")
}()
panic("我是panic")
fmt.Println("4")
}
打印
被recover捕获的panic 内容是:我是panic :string
1
3
2
- 只有最后一个panic会被recover捕获,
package main
import "fmt"
func main() {
defer_func()
}
func defer_func() {
defer func() {
if err := recover(); err != nil {
fmt.Println(err)
} else {
fmt.Println("哈哈")
}
}()
defer func() {
panic("defer内部触发的panic") // 这里会被打印
}()
panic("defer触发的panic")
}
单引号与双引号区别?
Golang中的单引号,更类似于C语言中的char类型,其实不能算字符串,因为只能是单个的字符。 Golang中的双引号,才是字符串,单行的,多个字符(字母数字)。 ... go里面双引号是字符串,单引号是字符,不存在单引号字符串
批量注释?
command + shirt+?
- 存在子函数,注意执行顺序,先压栈主函数 子函数 先进后出
package main
import "fmt"
func function(index int, value int) int {
fmt.Println(index)
return index
}
func main() {
defer function(1, function(3, 0))
defer function(2, function(4, 0))
}
后进先出 先进后出
3
4
2
1
结构体
数组可以存储同一类型的数据,结构体可以不同数据类型(静态语言)数组和切片 满足不了需求,需要结构体 结构体与类的概念
interface 多态结构体定义
package main
import "log"
type Person struct {
Name string
Age int
Labels map[string]string
}
func main(){
var p Person // 空值赋值
log.Printf("%v",p)
log.Printf("%+v",p)
}
===================
type Person struct {
Name string
Age int
Labels map[string]string
}
func main(){
var p = Person{Name:"xiaoyi"} // 自定义值初始化
log.Printf("%v",p)
log.Printf("%+v",p)
}
- 结构体赋值,关键字赋值 or 位置赋值(对应顺序) 类似类实例化对象 传参:
package main
import "log"
type Person struct {
Name string
Age int
Labels map[string]string
}
//全局变量
var p = Person{Name:"xiaoyi"}
func main(){
p1:=Person{
Age: 10,
Name: "熊阿姨",
Labels: map[string]string{},
}
p2:=Person{"lida",20,map[string]string{}}
//log.Printf("%v",p1)
log.Printf("%+v",p1)
log.Printf("%+v",p2)
}
- new和make
package main
import "log"
type Person struct {
Name string
Age int
Labels map[string]string
}
func main(){
p1 := new(Person)
p1 = &Person{
Age: 10,
Name: "小乙",
Labels: map[string]string{},
}
log.Printf(" %+v", p1)
}
- new返回类型的指针 make返回引用类型 select、channel、map
package main
import "log"
type Person struct {
Name string
Age int
Labels map[string]string
}
func main(){
var p1 *Person = new(Person)
p1.Name = "小姨"
p1.Age = 18
var p2 Person = Person{
Name: "ligui",
Age: 20,
Labels: nil,
}
log.Println(p1,p2)
// new返回 &{小姨 18 map[]} 返回值 {ligui 20 map[]}
}
操作属性:age+1
package main
import "log"
type Person struct {
Name string
Age int
Labels map[string]string
}
func main(){
p1:=Person{
Name: "abc",
Age: 18,
Labels: nil,
}
//访问属性
log.Printf("[p.name:%v][p.Age:%v]",p1.Name,p1.Age)
// 修改属性
p1.Age += 1
log.Printf("[p.name:%v][p.Age:%v]",p1.Name,p1.Age)
}
- 匿名结构体
- 匿名子弹没有字段名的字段
- 匿名字段 继承概念类似
package main
import (
"fmt"
"log"
)
type Person struct {
Name string
Age int
Labels map[string]string
}
type test struct {
name string
age int
int // 匿名字段
}
type Student struct {
StudentId int
Person //匿名结构体
}
func main(){
p1:=Person{
Name: "abc",
Age: 18,
}
s1 := Student{
StudentId: 123,
Person: p1,
}
fmt.Println(s1)
//访问属性 匿名继承
log.Printf("[p.name:%v][p.Age:%v]",p1.Name,p1.Age)
log.Printf("[s1.name:%v][s1.Age:%v]",s1.Name,s1.Age)
}
[p.name:abc][p.Age:18]
[s1.name:abc][s1.Age:18]
- 匿名嵌入 对属性操作
- 非匿名嵌入
- 场景:抽取公共字段 写cmdb 公共字段 common
package main
import (
"log"
)
type Person struct {
Name string
Age int
Labels map[string]string
}
type Student struct {
StudentId int
Person //匿名结构体
}
type Teacher struct {
TeacherId int
P Person //命名结构体
}
func main() {
p1 := Person{
Name: "xiaoyi",
Age: 18,
}
// 结构体匿名嵌入
s1 := Student{
StudentId: 123,
Person: p1,
}
log.Printf("[匿名结构体 可以直接访问继承的属性名][s1.name:%v][s1.Age:%v]", s1.Name, s1.Age)
log.Printf("[匿名结构体 可以加嵌入的结构体名称访问继承的属性名][s1.name:%v][s1.Age:%v]", s1.Person.Name, s1.Person.Age)
t1 := Teacher{
TeacherId: 456,
P: p1,
}
// 结构体的命名嵌入
log.Printf("[命名嵌入,访问继承的属性必须加上嵌入的字段名][t1.name:%v][t1.Age:%v]", t1.P.Name, t1.P.Age)
}
- 空指针 不能对属性进行操作
type Person struct {
Name string
Age int
Labels map[string]string
}
type Student struct {
StudentId int
Person //匿名结构体
}
type Teacher struct {
TeacherId int
P Person //命名结构体
}
type Teacher1 struct {
TeacherId int
*Person //结构体匿名 指针嵌入
}
func main() {
t1 := Teacher1{}
fmt.Println(t1) // {0 <nil>}
fmt.Println(t1.Age)
/*
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x1c798a]
goroutine 1 [running]:
main.main()
*/
}
- 结构体可见性
- 外部包 只能首字母大写可以被访问
- 同包内 不限制
package main
import (
"fmt"
"lugo03/tt"
)
// 外部包 结构体名和字段全大写
var a = tt.Test{X: 5}
// 同包 结构体名和字段可以小写
var b = Test2{x: 5}
var c = test3{x: 5}
func main() {
fmt.Println(a)
fmt.Println(b)
fmt.Println(c)
}
深浅拷贝
值类型 传值
引用类型 传指针
函数传参 == 值拷贝 就是深拷贝
值类型的数据,默认都是深拷贝
- int , float,string,bool,array,struct
## 引用类型的数据,默认都是浅拷贝
- slice,map,function
package main
import "log"
type Person struct {
Name string
Age int
}
func main() {
p1 := Person{
Name: "123",
Age: 123,
}
p2 := p1
p2.Age = 100
p1.Name = "456"
log.Printf("结构体中的字段都是值类型,那么就是深拷贝")
log.Printf("[p1的内存地址:%p ][value:%+v]", &p1, p1)
log.Printf("[p1的内存地址:%p ][value:%+v]", &p2, p2)
}
- 赋值给指针,浅拷贝
package main
import "log"
type Person struct {
Name string
Age int
}
func main() {
p1 := Person{
Name: "123",
Age: 123,
}
p2 := &p1 // 等同于 var p2 *Person p2 = &p1
log.Printf("结构体中的字段都是值类型,使用&赋值给另外一个,就是浅拷贝")
p1.Age = 19
(*p2).Name = "898"
log.Printf("[p1的内存地址:%p ][value:%+v]", &p1, p1)
log.Printf("[p2的内存地址:%p ][value:%+v]", p2, p2)
/*
2021/07/25 14:13:14 结构体中的字段都是值类型,使用&赋值给另外一个,就是浅拷贝
2021/07/25 14:13:14 [p1的内存地址:0xc000004078 ][value:{Name:898 Age:19}]
2021/07/25 14:13:14 [p2的内存地址:0xc000004078 ][value:&{Name:898 Age:19}]
*/
}
- 使用new方法 本身就是一个指针,可以直接赋值,2个指向相同的内存地址
package main
import "log"
type Person struct {
Name string
Age int
}
func main() {
p1 := new(Person)
p1.Name = "小乙"
p1.Age = 123
p2 := p1
//log.Printf("结构体中的字段都是值类型,使用&赋值给另外一个,就是浅拷贝")
p1.Age = 19
p2.Name = "898"
log.Printf("[p1的内存地址:%p ][value:%+v]", p1, p1)
log.Printf("[p2的内存地址:%p ][value:%+v]", p2, p2)
}
- map和切片是浅拷贝 值、数组都是深拷贝
package main
import "log"
type Person struct {
Name string
Age int
Tags map[string]string
HouseId1 [2]int // 数组是值类型
HouseId2 []int // 切片是引用类型
}
func main() {
p1 := Person{
Name: "小姨",
Age: 123,
Tags: map[string]string{"k1":"v1","k2":"v2"},
HouseId1: [2]int{100,101},
HouseId2: []int{200,201},
}
p2 := p1
// 修改两个值类型
p1.Age = 19
p2.Name = "898"
// 修改map
p1.Tags["k1"] = "v11"
// 修改array
p2.HouseId1[0] = 300
// 修改切片
p1.HouseId2[1] = 301
log.Printf("[p1的内存地址:%p ][value:%+v]", &p1, p1)
log.Printf("[p1的内存地址:%p ][value:%+v]", &p2, p2)
}
- 对里面引用类型重新赋值,可以实现深拷贝效果
package main
import "log"
type Person struct {
Name string
Age int
Tags map[string]string
HouseId1 [2]int // 数组是值类型
HouseId2 []int // 切片是引用类型
}
func main() {
p1 := Person{
Name: "小姨",
Age: 123,
Tags: map[string]string{"k1":"v1","k2":"v2"},
HouseId1: [2]int{100,101},
HouseId2: []int{200,201},
}
p2 := p1
// 针对其中引用类型的字段,重新赋值
// 对于map
m:=make(map[string]string)
for k,v:=range p1.Tags{
m[k] =v
}
p2.Tags = m
s1 := make([]int, 0)
for _, i := range p1.HouseId2 {
s1 = append(s1, i)
}
p2.HouseId2 = s1
// 修改两个值类型
p1.Age = 19
p2.Name = "898"
// 修改map
p1.Tags["k1"] = "v11"
// 修改array
p2.HouseId1[0] = 300
// 修改切片
p1.HouseId2[1] = 301
log.Printf("[p1的内存地址:%p ][value:%+v]", &p1, p1)
log.Printf("[p1的内存地址:%p ][value:%+v]", &p2, p2)
}
- 值类型 默认都是深拷贝 函数参数传递是值拷贝 值类型
- 引用类型 传递的是指针 默认浅拷贝
package main
import (
"encoding/json"
"log"
)
type Person struct {
Name string
Age int
Tags map[string]string
HouseId1 [2]int //数组是值类型
HouseId2 []int // 切片是引用类型
}
func main() {
p1 := Person{
Name: "小乙",
Age: 123,
Tags: map[string]string{"k1": "v1", "k2": "v2"},
HouseId1: [2]int{100, 101},
HouseId2: []int{200, 201},
}
var p2 Person
// 序列化为data
data, _ := json.Marshal(p1)
// 传递变量指针 实现引用类型 深拷贝
json.Unmarshal(data, &p2)
// 修改两个值类型的字段
p1.Age = 19
p2.Name = "898"
// 修改map
p1.Tags["k1"] = "v11"
// 修改array
p2.HouseId1[0] = 300
// 修改切片
p1.HouseId2[1] = 301
log.Printf("[p1的内存地址:%p ][value:%+v]", &p1, p1)
log.Printf("[p2的内存地址:%p ][value:%+v]", &p2, p2)
}
引用类型就是浅拷贝
面向对象 多态 接口实现
切片、map 入口结构体绑定方法 匿名嵌套 继承 调用绑定方法
package main
import (
"log"
)
type Person struct {
Name string
Age int
//Tags map[string]string
//HouseId1 [2]int //数组是值类型
//HouseId2 []int // 切片是引用类型
}
type Student struct {
Person // 匿名嵌套 实现继承
StudentId int
}
// 给Person结构体绑定一个SayHello
func (p Person) SayHello() {
log.Printf("[Person.SayHello][name:%v]", p.Name)
}
func main() {
p1 := Person{
Name: "小乙",
Age: 123,
}
s1 := Student{
Person: p1,
StudentId: 99,
}
s1.SayHello()
}
- 单例模式:
package main
import (
"log"
)
type Person struct {
Name string
Age int
}
type Student struct {
Person
StudentId int
}
// 给Person结构体绑定一个SayHello
func (p Person) SayHello() {
log.Printf("[Person.SayHello][name:%v]", p.Name)
}
// 传递指针
func (p *Person) ChangeAge1() {
p.Age += 10
log.Printf("[单实例绑定方法][Person.ChangeAge1][p.Age:%v]", p.Age)
}
func (p Person) ChangeAge2() {
p.Age += 10
log.Printf("[非指针型绑定][Person.ChangeAge2][p.Age:%v]", p.Age)
}
func main() {
p1 := Person{
Name: "小乙",
Age: 123,
}
s1 := Student{
Person: p1,
StudentId: 99,
}
s1.SayHello()
log.Println(s1.Age)
s1.ChangeAge1()
log.Println(s1.Age)
log.Println(s1.Age)
s1.ChangeAge2()
log.Println(s1.Age)
}
多态
- 灵魂 是有一个承载的容器,先把所有实现了接口的对象添加进来,遍历容器调用对应方法
- 鸭子模型 只要有鸭子特性就是鸭子 Python默认就是多态,没有类型区分
package main
import "log"
// 体现多态
// 告警通知的函数,根据不同的对象进行通知
//
type notifer interface {
// 通知方法
notify()
}
type user struct {
name string
email string
}
func (u *user) notify(){
log.Printf("[普通用户通知][notify to user:%s]",u.name)
}
type admin struct {
name string
age int
}
func (u *admin) notify(){
log.Printf("[管理员通知][notify to user:%s]",u.name)
}
// 多态统一调用入口
func sendNotify(n notifer){
n.notify()
}
func main(){
u1:=user{
name:"小姨",
email:"xx@qq.com",
}
a1:=admin{
name:"延期",
age:18,
}
// 直接调用结构体绑定方法
log.Println("直接调用结构体绑定方法")
u1.notify()
a1.notify()
// 体现多态
log.Println("体现多态")
sendNotify(&u1)
sendNotify(&a1)
// 灵魂
log.Println("多态灵魂承载容器")
ns := make([]notifer, 0)
ns = append(ns, &a1)
ns = append(ns, &u1)
for _, n := range ns {
n.notify()
}
}
- 多个数据源查询和推送数据:多态使用场景 先创建
package main
import (
"fmt"
"log"
)
// 多个数据源推送数据和查询数据
// query 查询数据
// push 方法写入数据
type DataSource interface {
//只能定义方法 or interface
Push(data string)
Query(name string) string
}
type redis struct {
Name string
Addr string
}
func (r *redis) Push(data string) {
// 真实应该推入它消息队列
log.Printf("[Pushdata][ds.name:%s][data:%s]", r.Name, data)
}
func (r *redis) Query(name string) string {
log.Printf("[Query.data][ds.name:%s][name:%s]", r.Name, name)
return name + r.Name
}
type kafka struct {
Name string
Addr string
}
func (k *kafka) Push(data string) {
// 真实应该推入它消息队列
log.Printf("[Pushdata][ds.name:%s][data:%s]", k.Name, data)
}
func (k *kafka) Query(name string) string {
log.Printf("[Query.data][ds.name:%s][name:%s]", k.Name, name)
return name + k.Name
}
// 灵魂容器
var DataSourceManager = make(map[string]DataSource)
// 注册方法
func register(name string, ds DataSource) {
DataSourceManager[name] = ds
}
func main() {
r := redis{
Name: "redis-6.0",
Addr: "1.1",
}
k := kafka{
Name: "kafka-2.11",
Addr: "2.2",
}
// 将数据源注册到承载的容器中
register("redis", &r)
register("kafka", &k)
// 模拟推送数据
for i := 0; i < 10; i++ {
key := fmt.Sprintf("key_%d", i)
for _, ds := range DataSourceManager {
ds.Push(key)
}
}
// 查询数据
for i := 0; i < 10; i++ {
key := fmt.Sprintf("key_%d", i)
for _, ds := range DataSourceManager {
log.Println(ds.Query(key))
}
}
}
- 空接口
所有的类型都实现了空接口
ok = true代表断言成功,
package main
import "fmt"
func main() {
var s interface{} = "abc"
s1, ok := s.(string)
fmt.Println(s1, ok)
s2, ok := s.(int)
fmt.Println(s2, ok)
}
- 断言判断类型,需要计算的时候i需要做断言
package main
import "fmt"
func main() {
var s interface{} = false
switch s.(type) {
case string:
fmt.Println("是个string")
case int:
fmt.Println("是个int")
default:
fmt.Println("未知的type")
}
}
logrus 的hook机制 github.com/sirupsen/logrus
- 错误处理
package main
import (
"log"
"os"
)
func main() {
f1, err := os.Stat("text.txt")
if err != nil { // 用的比较多 判断err返回值
switch err.(type) {
case *os.PathError:
log.Printf("PathError")
case *os.LinkError:
log.Printf("Linkerror")
case *os.SyscallError:
log.Printf("syscalerror")
}
} else {
log.Printf("f1:%v", f1)
}
}
- 自定义错误方法:
package main
import (
"errors"
"fmt"
)
type MyError struct {
err error // 继承error 是err
msg string
}
func (e *MyError) Error()string{
return e.err.Error() + e.msg
}
func main() {
err:=errors.New("原始错误")
MyErr :=MyError{
err: err,
msg: "附加信息",
}
fmt.Println(MyErr.Error()) // 调用方法和属性跟Python一样
}
- 注意 继承 和 接口
- 扩展都需要自定义一个方法,简化上面的方式,不需要定义一个结构体和方法,直接使用Errorf扩展错误
package main
import (
"errors"
"fmt"
)
func main() {
e1:=errors.New("原始错误")
e2:=fmt.Errorf("数据删除错误:%w",e1)
fmt.Println(e2)
}
IO操作
- 流操作 网络/文件/内存
package main
import (
"io"
"log"
"os"
"strings"
)
func main() {
reader:=strings.NewReader("xiaoyi 123wedn!1!")
//每次读取4个字节
p:=make([]byte,4)
for {
n,err := reader.Read(p)
if err!=nil{
if err==io.EOF{
log.Printf("读完了:eof错误:%d",n)
break
}
log.Printf("其他错误:%v",err)
os.Exit(2)
}
// 切片直接替换,最后一次就是p[:1]],只显示1个字符
log.Printf("[读取到的字节数为:%d][内容:%v]",n,string(p[:n]))
log.Printf("[读取到的字节数为:%d][内容:%v]",n,string(p))
// 直接打印p还是4个字节,会把上一次的切片进行替换,因为最后一次就一个字符,会显示上次的的是三个+这次1个字符
}
}
2021/07/25 17:06:49 [读取到的字节数为:1][内容:!]
2021/07/25 17:06:49 [读取到的字节数为:1][内容:!n!1]
- 以下代码展示了 alphaReader 如何与 os.File 结合以过滤掉文件中的非字母字符:
package main
import "fmt"
// 过滤字母外的字符串
func alpha(r byte) byte {
if (r >= 'A' && r < 'Z') || (r >= 'a' && r <= 'z') {
return r
}
return 0
}
func main() {
fmt.Println(alpha('z'))
fmt.Println(alpha('@'))
fmt.Println(alpha(' '))
}
- 组合Reader:
package main
import (
"fmt"
"io"
"log"
"strings"
)
type alphaReader struct {
// 组合io.reader
reader io.Reader
}
var a byte = 0
func (a *alphaReader) Read(p []byte) (int,error){
// 这里调用的是io.Reader
n,err:=a.reader.Read(p)
if err!=nil{
return n,err
}
buf :=make([]byte,n)
for i:=0;i<n;i++{
if char := goulv(p[i]);char!=0{
buf[i] = char
}
}
copy(p,buf)
return n,nil
}
// 过滤字母外的字符串
func goulv(r byte) byte {
if (r >= 'A' && r < 'Z') || (r >= 'a' && r <= 'z') {
return r
}
return 0
}
func main() {
fmt.Printf("a=%cAAAA\n", a)
originReader := strings.NewReader("xiaoYX(@dakdwd[1213kwdwd!!")
reader := alphaReader{
reader: originReader,
}
p1 := make([]byte, 4)
for {
n1, err := reader.Read(p1)
if err == io.EOF {
break
}
log.Printf("[][内容:%v]", string(p1[:n1]))
}
}
- 通过过滤实现不同的结果,跟原生的对比
package main
import (
"io"
"log"
"strings"
)
type alphaReader struct {
// 组合io.reader
reader io.Reader
}
func (a *alphaReader) Read(p []byte) (int,error){
// 这里调用的是io.Reader
n,err:=a.reader.Read(p)
if err!=nil{
return n,err
}
buf :=make([]byte,n)
for i:=0;i<n;i++{
if char := goulv(p[i]);char!=0{
buf[i] = char
}
}
copy(p,buf)
return n,nil
}
// 过滤字母外的字符串
func goulv(r byte) byte {
if (r >= 'A' && r < 'Z') || (r >= 'a' && r <= 'z') {
return r
}
return 0
}
func main() {
originReader := strings.NewReader("xiaoyi @12123wosasd")
reader:=alphaReader{
reader: strings.NewReader("xiaoyi @12123wosasd"),
}
p1:=make([]byte,4)
p2:=make([]byte,4)
for {
//n,err:=reader.Read(p)
n2,err:=originReader.Read(p2)
n1,err:=reader.Read(p1)
if err==io.EOF{
break
}
log.Printf("[p2内容:%v]",string(p2[:n2]))
log.Printf("[p1内容:%v]",string(p1[:n1]))
}
}
- 从文件读取 file中也有reader方法
package main
import (
"fmt"
"io"
"log"
"os"
)
var a byte = 0
type alphaReader struct {
// 组合io.reader
reader io.Reader
}
func (a *alphaReader) Read(p []byte) (int, error) {
// 这里调用的是io.Reader
n, err := a.reader.Read(p)
if err != nil {
return n, err
}
// 此时的p [xi@a] [xiao]
buf := make([]byte, n)
// buf = [0 0 0 0]
fmt.Println(buf)
for i := 0; i < n; i++ {
if char := guolv(p[i]); char != 0 {
buf[i] = char
}
}
fmt.Println(buf)
// buf = [79 68 0 65]
copy(p, buf)
return n, nil
}
// 只保留字符串中的字母字符 a-z A-Z
func guolv(r byte) byte {
if (r >= 'A' && r <= 'Z') || (r >= 'a' && r <= 'z') {
return r
}
return 0
}
func main() {
file,err:=os.Open("a.txt")
if err!=nil{
return
}
//originReader := strings.NewReader("xiaoYX(@dakdwd[1213kwdwd!!")
reader := alphaReader{
reader: file,
}
p1 := make([]byte, 4)
for {
n1, err := reader.Read(p1)
if err == io.EOF {
break
}
log.Printf("[][内容:%v]", string(p1[:n1]))
}
}
- 工具包 里面的ioutil 读取文件内容:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
bytes,err:=ioutil.ReadFile("go.mod")
// 空指针 会导致panic 异常捕获是recover panic是捕获的输出
// 不判断如果是空 就会导致panic
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%s", bytes)
fmt.Printf("%v", string(bytes))
}
- 写文件,写入到a,txt方法
package main
import (
"fmt"
"io/ioutil"
)
func main() {
fileName := "a.txt"
err := ioutil.WriteFile(fileName, []byte("升职加薪\n迎娶白富美"), 0644)
fmt.Println(err)
}
- 遍历文件夹:
package main
import (
"io/ioutil"
"log"
)
func main() {
fs,_:=ioutil.ReadDir("../lugo03")
for _,f:=range fs{
log.Printf("[name:%v][size:%v][mode:%v][modtime:%v]",
f.Name(),
f.Size(),
f.Mode(),
f.ModTime())
}
}
- 写文件,os创建文件写内容
package main
import "os"
func main() {
file,_:=os.Create("b.txt")
for i:=0;i<5;i++{
file.WriteString("writeString\n")
file.Write([]byte("write\n"))
}
}
对常用系统操作:
package main
import (
"log"
"os"
)
func main() {
hn, _ := os.Hostname()
log.Printf("主机名:%v", hn)
log.Printf("进程pid:%v", os.Getpid()) // 操作kill自己 自升级 systemd自动拉起
log.Printf("命令行参数:%v", os.Args)
log.Printf("获取goroot环境变量:%v", os.Getenv("GOROOT"))
for _, v := range os.Environ() {
log.Printf("环境变量 %v", v)
}
dir, _ := os.Getwd()
log.Printf("当前目录 %v", dir)
log.Printf("创建单一config目录")
//err := os.Mkdir("config",0755)
os.Mkdir("config",0755)
log.Printf("创建层级config/yaml/local目录")
os.MkdirAll("config/yaml/local",0755)
log.Printf("删除单一文件或目录",os.Remove("config"))
log.Printf("删除层级文件或目录",os.RemoveAll("config1"))
}