• I/O操作、go module


    目录:

    1:I/O操作

    2:go module是什么

    一、I/O操作

    • 流(stream)是应用程序和外部资源进行数据交互的纽带

    • 流分为输入流和输出流,输入和输出都是相对于程序,把外部数据传入到程序中叫做输入,反之叫做输出流

    • 输入流(Input Stream),输入流(Output Stream) 平时所说的I/O流

    • 在Go语言标准库中io包下是Reader接口表示输入流,只要实现这个接口就属于输入流

    • io库比较常用的接口有三个,分别是Reader,Writer和Closer。

    1.1:读文件(Reader

    可以使用strings包下的NewReader创建字符串流

     最常用的是文件流,把外部文件中数据读取到程序中

    func main() {
    	f, err := os.Open("D:/go.txt")//打开文件
    	defer f.Close()
    	if err != nil {
    		fmt.Println("文件读取失败,", err)
    		return
    	}
    	fileInfo, err := f.Stat()//获取文件信息
    	if err != nil {
    		fmt.Println("文件信息获取失败,", err)
    		return
    	}
    	b := make([]byte, fileInfo.Size())//根据文件中数据大小创建切片
    	_, err = f.Read(b)//读取数据到切片中
    	if err != nil {
    		fmt.Println("文件流读取失败:", err)
    		return
    	}
    	fmt.Println("文件中内容为:", string(b))//以字符串形式输入切片中数据
    }
    

    1.2:写文件(Writer

    输入流就是把程序中数据写出到外部资源

    Go语言标准库中输出流是Writer接口

    type Writer interface {
        //Write() 方法有两个返回值,一个是写入到目标资源的字节数,一个是发生错误时的错误。
        Write(p []byte) (n int, err error)
    }
    
    • io.Writer 表示一个写入器,它从缓冲区读取数据,并将数据写入目标资源。

    • 对于要用作编写器的类型,必须实现 io.Writer 接口的唯一一个方法 Write(p []byte)

    • 同样,只要实现了 Write(p []byte) ,那它就是一个编写器。

    写文件

    package main
    
    import (
        "fmt"
        "os"
    )
    
    func main() {
        // 新建文件
        file, err := os.Create("./test.txt")
        if err != nil {
            fmt.Println(err)
            return
        }
        defer file.Close()
        for i := 0; i < 5; i++ {
            file.WriteString("ab\n")
            file.Write([]byte("cd\n"))
        }
    }
    

    第二种

    	fp := "D:/go.txt"
    	/*
    	第三个参数表示文件权限
    	第 1 位在权限中总是为 0
    	第 2 位为 0 表示文件不可以被读, 为 1 表示可以被读
    	第 3 位为 0 表示文件不可以被写, 为 1 表示可以被写
    	第 4 位为 0 表示文件不可以被执行, 为 1 表示可以被执行
    	整理如下:
    	   0(0000): 不可读写,不能被执行
    	   1(0001): 不可读写,能被执行
    	   2(0010): 可写不可读,不能被执行
    	   3(0011): 可写不可读,能被执行
    	   4(0100): 可读不可写,不能被执行
    	   5(0101): 可读不可写,能被执行
    	   6(0110): 可读写,不能执行
    	   7(0111): 可读写,可执行
    
    	0666:
    	第一个 0 表示这个数是 八进制
    	第一个 6 表示文件拥有者有读写权限,但没有执行权限
    	第二个 6 表示文件拥有者同组用户有读写权限,但没有执行权限
    	第三个 6 表示其它用户有读写权限,但没有执行权限
    
    	 */
    
    	//第二个参数表示文件内容追加
    	//第三个参数表示创建文件时文件权限
    	f, err := os.OpenFile(fp, os.O_APPEND, 0660)
    	defer f.Close()
    	if err != nil {
    		fmt.Println("文件不存在,创建文件")
    		f, _ = os.Create(fp)
    	}
    
    	/*
    	内容中识别特殊字符
    	\r\n 换行
    	\t 缩进
    	 */
    
    	/*
    	使用文件对象重写的Writer接口,参数是[]byte
    	 */
    	f.Write([]byte("使用Writer接口写数据\r\n"))
    
    	/*
    	使用stringWriter接口的方法,参数是字符串,使用更方便
    	 */
    	f.WriteString("写了\t一段\r\n内容123")
    	fmt.Println("程序执行结束")

    1.3:文件操作相关API

    1.4:对IO封装的工具包

    1.4.1: bufio
    • bufio包实现了带缓冲区的读写,是对文件读写的封装

    • bufio缓冲写数据

     读写数据

    package main
    
    import (
        "bufio"
        "fmt"
        "io"
        "os"
    )
    
    func wr() {
        // 参数2:打开模式,所有模式d都在上面
        // 参数3是权限控制
        // w写 r读 x执行   w  2   r  4   x  1
        //特殊权限位,拥有者位,同组用户位,其余用户位
        file, err := os.OpenFile("./xxx.txt", os.O_CREATE|os.O_WRONLY, 0666)
        if err != nil {
            return
        }
        defer file.Close()
        // 获取writer对象
        writer := bufio.NewWriter(file)
        for i := 0; i < 10; i++ {
            writer.WriteString("hello\n")
        }
        // 刷新缓冲区,强制写出
        writer.Flush()
    }
    
    func re() {
        file, err := os.Open("./xxx.txt")
        if err != nil {
            return
        }
        defer file.Close()
        reader := bufio.NewReader(file)
        for {
            line, _, err := reader.ReadLine()
            if err == io.EOF {
                break
            }
            if err != nil {
                return
            }
            fmt.Println(string(line))
        }
    
    }
    
    func main() {
        re()
    }
    
    1.4.2: ioutil工具包
    • ioutil库包含在io目录下,它的主要作用是作为一个工具包,里面有一些比较实用的函数

    • 比如 ReadAll(从某个源读取数据)、ReadFile(读取文件内容)、WriteFile(将数据写入文件)、ReadDir(获取目录)

    package main
    
    import (
       "fmt"
       "io/ioutil"
    )
    
    func wr() {
       err := ioutil.WriteFile("./yyy.txt", []byte("码神之路"), 0666)
       if err != nil {
          fmt.Println(err)
          return
       }
    }
    
    func re() {
       content, err := ioutil.ReadFile("./yyy.txt")
       if err != nil {
          fmt.Println(err)
          return
       }
       fmt.Println(string(content))
    }
    
    func main() {
       re()
    }
    

     二、包

    包和python一样的意思

    包的习惯用法:

    • 包名一般是小写的,使用一个简短且有意义的名称。

    • 包名一般要和所在的目录同名,也可以不同,包名中不能包含-等特殊符号。

    • 包名为 main 的包为应用程序的入口包,编译不包含 main 包的源码文件时不会得到可执行文件。

    • 一个文件夹下的所有源码文件只能属于同一个包,同样属于同一个包的源码文件不能放在多个文件夹下。

    go文件的搜索路径

    包的绝对路径就是GOROOT/src/GOPATH后面包的存放路径,如下所示:

     import "lab/test"
     import "database/sql/driver"
     import "database/sql"

    上面代码的含义如下:

    • test 包是自定义的包,其源码位于GOPATH/lab/test目录下;

    • driver 包的源码位于GOROOT/src/database/sql/driver目录下;

    • sql 包的源码位于GOROOT/src/database/sql目录下。

    三、go module

    3.1:为什么要使用go module?

    我们要知道在python里面可以使用  pip install bce-python-sdk==0.8.64 安装第三方模块的时候可以指定版本,但是在go里面怎么进行版本控制呢?

    没错,是需要要用go module这个玩意的!

    go module 是Go语言从 1.11 版本之后官方推出的版本管理工具,并且从 Go1.13 版本开始,go module 成为了Go语言默认的依赖管理工具。

    3.2:go module的环境配置

    使用go module之前需要设置环境变量:

    GO111MODULE=on   #中间111是为了记录1.11版本开始有了go module
    GOPROXY=https://goproxy.io,direct
    GOPROXY=https://goproxy.cn,direct(好心人PQ:国内的七牛云提供)

    GO111MODULE 有三个值:off, on和auto(默认值)。

    • GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种通过vendor目录或者GOPATH模式来查找。

    • GO111MODULE=on,go命令行会使用modules,而一点也不会去GOPATH目录下查找。

    • GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:

      • 当前目录在GOPATH之外且该目录包含go.mod文件 开启

      • 当处于 GOPATH 内且没有 go.mod 文件存在时其行为会等同于 GO111MODULE=off

    • 如果不使用 Go Modules, go get 将会从模块代码的 master 分支拉取

    • 而若使用 Go Modules 则你可以利用 Git Tag 手动选择一个特定版本的模块代码

    3.3:go module 的命令使用

    我们知道node.js 在创建一个工程的时候要执行npm init 。

    在go里面我们想创建一个新的工程的时候,需要执行 go mod init [工程名字]

    go mod 有以下命令:

     比较常用的命令,记住就好了:

    • 常用的有 init tdiy edit

    使用go get命令下载指定版本的依赖包:

    执行go get命令,在下载依赖包的同时还可以指定依赖包的版本。

    • 运行go get -u命令会将项目中的包升级到最新的次要版本或者修订版本;

    • 运行go get -u=patch命令会将项目中的包升级到最新的修订版本;

    • 运行go get [包名]@[版本号]命令会下载对应包的指定版本或者将对应包升级到指定的版本。

    提示:go get [包名]@[版本号]命令中版本号可以是 x.y.z 的形式,例如 go get foo@v1.2.3,也可以是 git 上的分支或 tag,例如 go get foo@master,还可以是 git 提交时的哈希值,例如 go get foo@e3702bed2。

    3.4:项目中使用go module

    3.4.1:初始化项目 

    在 GOPATH 目录下新建一个目录,并使用go mod init 【工程名字】 初始化生成 go.mod 文件。
    

    go.mod 文件一旦创建后,它的内容将会被 go toolchain 全面掌控,go toolchain 会在各类命令执行时,比如go getgo buildgo mod等修改和维护 go.mod 文件。

    3.4.2:代码添加一个依赖

    main.go

     package main
     import (
         "net/http"
         "github.com/labstack/echo"
     )
     func main() {
         e := echo.New()
         e.GET("/", func(c echo.Context) error {
             return c.String(http.StatusOK, "Hello, World!")
         })
         e.Logger.Fatal(e.Start(":1323"))
     }
    

    3.4.3:下载依赖

    执行go mod tidy运行代码会发现 go mod 会自动查找依赖自动下载
    

    3.4.4:拉取代码原则

    go module 安装 package 的原则是先拉取最新的 release tag,若无 tag 则拉取最新的 commit

    go 会自动生成一个 go.sum 文件来记录 dependency tree。
    执行脚本go run main.go,就可以运行项目。
    
    可以使用命令go list -m -u all来检查可以升级的 package,使用go get -u need-upgrade-package升级后会将新的依赖版本更新到 go.mod ,
    比如:go get -u github.com/labstack/gommon
    
    也可以使用go get -u升级所有依赖。
    一般使用包之前,是首先执行go get命令,先下载依赖。比如 github.com/labstack/echo

    使用 replace 替换无法直接获取的 package:

    由于某些已知的原因,并不是所有的 package 都能成功下载,比如:golang.org 下的包。

    modules 可以通过在 go.mod 文件中使用 replace 指令替换成 github 上对应的库,比如:

     replace (
         golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
     ) 

    或者

     replace golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a

    go install命令将项目打包安装为可执行文件,在安装在GOPATH的bin目录下,go install执行的项目 必须有main方法

     

  • 相关阅读:
    Linux文件/proc/net/tcp分析
    为什么系统调用会消耗较多资源
    为什么Linux默认页大小是4KB
    为什么Linux需要虚拟内存
    Make 命令教程
    关于同步的一点思考-下
    关于同步的一点思考-上
    Linux下的进程控制块(PCB)
    汇编语言基础:寄存器和系统调用
    内核栈与thread_info结构详解
  • 原文地址:https://www.cnblogs.com/hero799/p/15956389.html
Copyright © 2020-2023  润新知