I/O操作、go module
目录:
1:I/O操作
2:go module是什么
一、I/O操作
-
-
流分为输入流和输出流,输入和输出都是相对于程序,把外部数据传入到程序中叫做输入,反之叫做输出流
-
输入流(Input Stream),输入流(Output Stream) 平时所说的I/O流
-
-
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:写文件(
)
type Writer interface { //Write() 方法有两个返回值,一个是写入到目标资源的字节数,一个是发生错误时的错误。 Write(p []byte) (n int, err error) }
-
-
对于要用作编写器的类型,必须实现 io.Writer 接口的唯一一个方法 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.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库包含在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之前需要设置环境变量:
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 有以下命令:
比较常用的命令,记住就好了:
使用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 get
、go build
、go 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方法