day04 课上笔记


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  floatstringboolarraystruct

## 引用类型的数据默认都是浅拷贝
- slicemapfunction
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"))

}