log
log 是内置模块,无需导入
# 直接打印
log.Print("Hey, I'm a log!")
2020/12/19 13:39:17 Hey, I'm a log!
# 设置前缀
log.SetPrefix("main():")
main(): 2021/01/05 13:59:58 Hey, I'm a log!
# 输出日志的同时退出程序,就如同执行os.Exit(1)
log.Fatal("Hey, I'm an error log!")
# 输出日志的同时执行 panic()
log.Panic("Hey, I'm an error log!")
# 输出日志到文件,file是打开的文件描述符
log.SetOutput(file)
log.Print("Hey, I'm a log!")
zerolog
日志框架,扩展log模块。通过日志框架可以设置日志级别或者配置不同的日志输出。
go get -u github.com/rs/zerolog/log
package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
)
func main(){
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
log.Print("Hey!I'm a log message")
log.Debug().
Int("EmployeeID", 1001).
Msg("Getting Employee Information")
log.Debug().Str("Name", "John").Send()
}
输出:
{"level":"debug","time":1645513637,"message":"Hey!I'm a log message"}
{"level":"debug","EmployeeID":1001,"time":1645513637,"message":"Getting Employee Information"}
{"level":"debug","Name":"John","time":1645513637}
os
文件
os.OpenFile
func OpenFile(name string, flag int, perm FileMode) (*File, error)
os.OpenFile
根据flag
模式来创建/打开一个文件
这里的返回值*File
其实也是io.Reader
,都是textual I/O这一类. 因此,*File
也可以被用于bufio
和io
模块
常用的flag组合:
os.O_CREATE|os.O_RDWR
创建并可读可写
os.O_CREATE|os.O_RDWR|os.O_APPEND
创建并可读可写可追加
⚠️需要注意的是,os.O_APPEND
将始终如一的将指针定位到尾部,因此*File.Seek
无法使用,所以你也无法实现计算文件行数之类的方法(因为你无法定位到首部)。
全路径
os.Executable() 返回可执行程序的全路径
func Executable() (string, error)
⚠️ 但在符号链接的情况下,可能返回的是符号链接的路径或者其指向的路径
命令行参数
os.Args []string
,其os.Args[0]
是程序名
退出程序
os.Exit(code int) ,以指定的code退出程序,按照通常做法,你应该以0
表示正常退出,非0
表示异常
⚠️它会导致defer
不执行
os/user
获取当前用户信息
userInfo, err := user.Current()
if err != nil {
fmt.Println("Error: get current user")
} else {
userName := userInfo.Username
}
os/exec
执行命令
cmd := appPath + " " + appArgs
if _, err := exec.LooPath(appPath); err != nil {
fmt.Printf("Error: %s not found\n", appPath)
} else {
c := exec.Command("bash", "-c", cmd)
output, err := c.CombineOutput()
if err != nil {
fmt.Printf("Error: %s\n", output)
} else {
fmt.Printf("Success: %s\n", output)
}
}
bytes
字节对比
if bytes.Equal(aByte, bByte) {
fmt.Println("两者相同")
}
path/filepath
获取文件名和路径
if fullPath, err := os.Executable() ; err != nil {
fmt.Printf("Error executing")
} else {
basePath, baseName := filepath.Split(fullPath)
}
bufio
实现带缓存的I/O
io 和 os
读写文件或者文件描述符的内容
💁另外,io/ioutil 也可以实现io和os里的一些文件相关的方法,但是他们已经迁移到了io和os
fd, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
defer fd.Close()
if err != nil {
fmt.Printf("Error(open): %s\n", filePath)
} else {
fByte, err := io.ReadAll(fd)
if err != nil {
fmt.Printf("Error(read): %s\n", err)
} else {
fmt.Printf("file content:\n %s\n", fByte)
}
}
mysql
sql package - database/sql - pkg.go.dev
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
func main(){
mysqlConnect := fmt.Sprintf("%s:%s@tcp(%s)/mysql", conf.Database.Username, conf.Database.Password, conf.Database.Host)
if err != nil {
errors.New("Error mysql connect")
return
}
db.SetConnMaxLifetime(100*time.Second) //最大连接周期,超过时间的连接就close
db.SetMaxOpenConns(10) //设置最大连接数
db.SetMaxIdleConns(5) //设置闲置连接
rows, err := db.Query("show full processlist")
if err != nil {
errors.New("Error db Query")
return
}
var Id,Time int64
var User, Host, Command, State string
var Db, Info sql.NullString
for rows.Next() {
rows.Scan(&Id, &User, &Host, &Db, &Command, &Time, &State, &Info)
fmt.Printf("%d,%s,%s,%s,%s,%d,%s,\"%s\"\n", Id, User, Host, Db.String, Command, Time, State, Info.String
}
rows.Next()
读取一行,并指向行尾
rows.Scan(dest ...interface{})
将当前行的值逐个字段的复制给dest,dest是指针类型。dest顺序和当前行的字段顺序需要一一对应。
gopkg.in/gomail.v2
gomail package - gopkg.in/gomail.v2 - pkg.go.dev
func sendEmail(smtpServer string, smtpPort int, smtpUser string, smtpPassword string, receiveUser []string, subject string, content string, attach string) error {
m := gomail.NewMessage()
m.SetHeader("From", smtpUser)
m.SetHeader("To", receiveUser...)
m.SetHeader("Subject", subject)
m.SetBody("text/html", content)
m.Attach(attach)
d := gomail.NewDialer(smtpServer, smtpPort, smtpUser, smtpPassword)
err := d.DialAndSend(m)
return err
}
gopkg.in/yaml.v3
yaml package - gopkg.in/yaml.v3 - pkg.go.dev
配置文件示例
email:
smtpserver: smtp.feishu.cn
smtpport: 465
smtpuser:
smtppassword:
receiveuser:
- [email protected]
subject:
content:
database:
host:
username:
password:
timeout:
//映射配置文件的结构体
type Config struct {
Email struct {
Smtpserver string `yaml:"smtpserver"`
Smtpport int `yaml:"smtpport"`
Smtpuser string `yaml:"smtpuser"`
Smtppassword string `yaml:"smtppassword"`
Receiveuser []string `yaml:"receiveuser"`
Subject string `yaml:"subject"`
Content string `yaml:"content"`
}
Database struct {
Host string `yaml:"host"`
Username string `yaml:"username"`
Password string `yaml:"password"`
Timeout int64 `yaml:"timeout"`
}
}
//实现结构体方法 getConf
func (config *Config) getConf(confPath string) (*Config) {
yamlFile, err := ioutil.ReadFile(confPath)
if err != nil {
fmt.Println("Error reading config")
}
err = yaml.Unmarshal(yamlFile, config)
if err != nil {
fmt.Println("Error unmarshaling config")
}
return config
}
func main(){
var config Config
conf := config.getConf("/to_path/config.yaml")
fmt.Println(conf.Email.Smtpserver)
}
⚠️定义配置文件映射的结构体的时候,属性首字母要大写
encoding/json
https://pkg.go.dev/encoding/json
https://json2struct.mervine.net/ json转struct
构造json对象,用来传递参数
import "encoding/json"
postMap := map[string]string{"username": username, "password": password}
postJson, err := json.Marshal(postMap) // postJson 已经是[]byte
if err != nil {
fmt.Println("Error:json.Marshal")
}
解析json对象,获取对象值
import (
"encoding/json"
"fmt"
)
func main(){
var bodyByte = []byte(`[
{"Name": "Platypus", "Order": "Monotremata"},
{"Name": "Quoll", "Order": "Dasyuromorphia"}
]`)
type Animal struct {
Name string
Order string
}
var animals []Animal
if err := json.Unmarshal(bodyByte, &animals); err != nil {
fmt.Println(err)
} else {
for _, val := range animals {
fmt.Printf("Name:%s, Order:%s\n", val.Name, val.Order)
}
}
}
输出:
Name:Platypus, Order:Monotremata
Name:Quoll, Order:Dasyuromorphia
注意点
以小写字母开头的结构体字段不会被编码进去
package main
import (
"fmt"
"encoding/json"
)
type MyData struct {
One int
two string
}
func main() {
in := MyData{1,"two"}
fmt.Printf("%#v\n",in) //prints main.MyData{One:1, two:"two"}
encoded,_ := json.Marshal(in)
fmt.Println(string(encoded)) //prints {"One":1} 这里可以看出two:"two"没有被编码进去
var out MyData
json.Unmarshal(encoded,&out)
fmt.Printf("%#v\n",out) //prints main.MyData{One:1, two:""}
}
time
time package - time - pkg.go.dev
go采用一种很独特的方式来格式化时间,即:
2006数字代表年,如同常见的%Y
01数字代表月,如同常见的%m
02数字代表日
15数字代表时(24小时的下午三点)
04数字代表分
05数字代表秒
Z07数字代表时区(-07也可以)
整体记忆方法就是:01、02、15(03)、04、05、2006(06)、Z07(07)
time.Now().Format("2006.01.02 15:04:05 Z07")
转时区
package main
import (
"fmt"
"time"
)
func main(){
currenttime := time.Now()
time_zone, _ := time.LoadLocation("Asia/Shanghai")
fmt.Println(currenttime.In(time_zone).Format("2006-01-02-15-04-05"))
}
net/http
import "net/http"
func GetUser(url, path, username string, password string) (UserJson, error) {
client := &http.Client{} // 创建客户端
postMap := map[string]string{"username": username, "password": password}
postJson, err := json.Marshal(postMap)
if err != nil {
fmt.Println("Error json.Marshal")
}
request, err := http.NewRequest(http.MethodPost, url+path, bytes.NewBuffer(postJson)) // 创建请求体
if err != nil {
fmt.Println("Error http.NewRequest")
}
request.Header.Set("Content-Type", "application/json") // 添加类型
response, err := client.Do(request)
if err != nil {
fmt.Println("Error client do request")
}
bodyByte, err := io.ReadAll(response.Body)
defer response.Body.Close()
var user UserJson
if err := json.Unmarshal(bodyByte, &user); err != nil {
fmt.Println("Error json unmarshal response userjson")
}
return user, err
}
func main() {
myuser, err := GetUser(acmeServer, "/api/user/", authuser, authpasswd)
}