go语言常用标准库
go语言常用标准库
fmt
print和printn就不介绍了
fmt.Printf
printf是可以格式化输出,你可以想一想你学的c语言
主要讲一下占位符
package main
import "fmt"
func main() {
name := "John"
age := 28
isMarried := false
salary := 5000.5
// 输出字符串,使用 %s
fmt.Printf("His name is %s.\n", name) // His name is John.
// 输出整数,使用 %d
fmt.Printf("He is %d years old.\n", age) // He is 28 years old.
// 输出布尔值,使用 %t
fmt.Printf("Is he married? %t\n", isMarried) // Is he married? false
// 输出浮点数,使用 %f
fmt.Printf("His salary is %f.\n", salary) // His salary is 5000.5.
// 使用 %v 会自动选择合适的格式
fmt.Printf("His name is %v, he is %v years old, is he married? %v, his salary is %v.\n",
name, age, isMarried, salary)
// His name is John, he is 28 years old, is he married? false, his salary is 5000.5.
// 使用 %+v 和 %#v 打印更详细的信息
type Person struct {
Name string
Age int
}
john := Person{Name: "John", Age: 28}
fmt.Printf("John: %+v\n", john) // John: {Name:John Age:28}
fmt.Printf("John: %#v\n", john) // John: main.Person{Name:"John", Age:28}
// 使用 %T 打印变量的类型
fmt.Printf("Type of john: %T\n", john) // Type of john: main.Person
}
Fprint
Fprint系列函数会将内容输出到一个io.Writer接口类型的变量w中,我们通常用这个函数往文件中写入内容。
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Create("file.txt")
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
name := "John"
age := 28
fmt.Fprint(f, "His name is ", name, ".") // 写入到 file.txt: His name is John.
fmt.Fprintln(f, "He is ", age, " years old.") // 写入到 file.txt: He is 28 years old.\n
fmt.Fprintf(f, "His name is %s, he is %d years old.", name, age) // 写入到 file.txt: His name is John, he is 28 years old.
}
fmt.Fprint 系列函数也被广泛用于 HTTP 服务器的开发中,向客户端返回响应。以下是一个简单的 HTTP 服务器:
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Query().Get("name")
if name == "" {
name = "World"
}
// 使用 fmt.Fprintf 向 http.ResponseWriter 写入响应
fmt.Fprintf(w, "Hello, %s!", name)
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
http.ResponseWriter 是满足 io.Writer 接口的,所以我们可以直接使用 fmt.Fprint 向其写入数据
在这里,当我们传入name参数时,就可以使用它去把我们传入的name写入到response
fmt.Scan
这个还是和c语言一样,这个是获取输入的
package main
import "fmt"
func main() {
var (
name string
age int
married bool
)
fmt.Scan(&name, &age, &married)
fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
}
当然scanf就不讲了
Fscan
他就是和Fprint对应的
它就是从文件的读取数据了
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("data.txt")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file.Close()
var name string
var age int
// Assume that data.txt contains lines in the format "name age"
for {
_, err := fmt.Fscan(file, &name, &age)
if err != nil {
if err == io.EOF {
break // end of file reached
}
fmt.Println("Error reading file:", err)
return
}
fmt.Printf("Name: %s, Age: %d\n", name, age)
}
}
打开 data.txt 文件,然后在一个循环中使用 fmt.Fscan 读取并解析每一行的数据。
Time
时间类型
func timeDemo() {
now := time.Now() //获取当前时间
fmt.Printf("current time:%v\n", now)
year := now.Year() //年
month := now.Month() //月
day := now.Day() //日
hour := now.Hour() //小时
minute := now.Minute() //分钟
second := now.Second() //秒
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}
时间戳
时间戳是自1970年1月1日(08:00:00GMT)至当前时间的总毫秒数。它也被称为Unix时间戳(UnixTimestamp)。
基于时间对象获取时间戳的示例代码如下:
func timestampDemo() {
now := time.Now() //获取当前时间
timestamp1 := now.Unix() //时间戳
timestamp2 := now.UnixNano() //纳秒时间戳
fmt.Printf("current timestamp1:%v\n", timestamp1)
fmt.Printf("current timestamp2:%v\n", timestamp2)
}
使用time.Unix()函数可以将时间戳转为时间格式。
func timestampDemo2(timestamp int64) {
timeObj := time.Unix(timestamp, 0) //将时间戳转为时间格式
fmt.Println(timeObj)
year := timeObj.Year() //年
month := timeObj.Month() //月
day := timeObj.Day() //日
hour := timeObj.Hour() //小时
minute := timeObj.Minute() //分钟
second := timeObj.Second() //秒
fmt.Printf("%d-%02d-%02d %02d:%02d:%02d\n", year, month, day, hour, minute, second)
}
时间操作
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println("当前时间:", now)
later := now.Add(time.Hour)
fmt.Println("一小时后:", later)
subtime := now.Sub(later)
fmt.Println("时间差:", subtime)
equal := now.Equal(later)
fmt.Println("时间是否相等:", equal)
before := now.Before(later)
fmt.Println("现在是否早于一小时后:", before)
// 计算当前时间与指定时间的时间差
diff := now.Sub(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC))
fmt.Println("与2023年1月1日的时间差:", diff)
}
IO操作
输入输出
os.Stdin:标准输入的文件实例,类型为File
os.Stdout:标准输出的文件实例,类型为File
os.Stderr:标准错误输出的文件实例,类型为*File
文件操作
func Create(name string) (file *File, err Error)
根据提供的文件名创建新的文件,返回一个文件对象,默认权限是0666
func NewFile(fd uintptr, name string) *File
根据文件描述符创建相应的文件,返回一个文件对象
func Open(name string) (file *File, err Error)
只读方式打开一个名称为name的文件
func OpenFile(name string, flag int, perm uint32) (file *File, err Error)
打开名称为name的文件,flag是打开的方式,只读、读写等,perm是权限
func (file *File) Write(b []byte) (n int, err Error)
写入byte类型的信息到文件
func (file *File) WriteAt(b []byte, off int64) (n int, err Error)
在指定位置开始写入byte类型的信息
func (file *File) WriteString(s string) (ret int, err Error)
写入string信息到文件
func (file *File) Read(b []byte) (n int, err Error)
读取数据到b中
func (file *File) ReadAt(b []byte, off int64) (n int, err Error)
从off开始读取数据到b中
func Remove(name string) Error
删除文件名为name的文件
打开和关闭文件
package main
import (
"fmt"
"os"
)
func main() {
// 只读方式打开当前目录下的main.go文件
file, err := os.Open("./main.go")
if err != nil {
fmt.Println("open file failed!, err:", err)
return
}
// 关闭文件
file.Close()
}
读写拷贝文件
写文件
package main
import (
"fmt"
"os"
)
func main() {
// 新建文件
file, err := os.Create("./xxx.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"))
}
}
读文件
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开文件
file, err := os.Open("./xxx.txt")
if err != nil {
fmt.Println("open file err :", err)
return
}
defer file.Close()
// 定义接收文件读取的字节数组
var buf [128]byte
var content []byte
for {
n, err := file.Read(buf[:])
if err == io.EOF {
// 读取结束
break
}
if err != nil {
fmt.Println("read file err ", err)
return
}
content = append(content, buf[:n]...)
}
fmt.Println(string(content))
}
拷贝文件
package main
import (
"fmt"
"io"
"os"
)
func main() {
// 打开源文件
srcFile, err := os.Open("./xxx.txt")
if err != nil {
fmt.Println(err)
return
}
// 创建新文件
dstFile, err2 := os.Create("./abc2.txt")
if err2 != nil {
fmt.Println(err2)
return
}
// 缓冲读取
buf := make([]byte, 1024)
for {
// 从源文件读数据
n, err := srcFile.Read(buf)
if err == io.EOF {
fmt.Println("读取完毕")
break
}
if err != nil {
fmt.Println(err)
break
}
//写出去
dstFile.Write(buf[:n])
}
srcFile.Close()
dstFile.Close()
}
bufio
bufio 包实现了缓存I/O。它提供了bufio.Reader和bufio.Writer类型,其内部分别包装了io.Reader和io.Writer对象,同时分别实现了io.Reader和io.Writer接口。同时,该包为文本I/O提供了一些便利操作。
os.O_WRONLY 只写
os.O_CREATE 创建文件
os.O_RDONLY 只读
os.O_RDWR 读写
os.O_TRUNC 清空
os.O_APPEND 追加
bufio.Reader 类型
NewReader() 函数用于创建一个带缓冲的读取器,它从指定的 io.Reader 中读取数据并提供缓冲机制。
Reader 类型提供了 Read() 方法,用于从缓冲区读取数据,并在缓冲区为空时填充缓冲区。
示例:
data := []byte("Hello, World!")
reader := bufio.NewReader(bytes.NewReader(data))
buffer := make([]byte, 5)
for {
n, err := reader.Read(buffer)
if err != nil && err != io.EOF {
fmt.Println("Error:", err)
break
}
if n == 0 {
break
}
fmt.Println(string(buffer[:n]))
}
bufio.Writer
NewWriter() 函数用于创建一个缓冲写入器,它将数据写入指定的 io.Writer。
Writer 类型提供了 Write() 方法,用于将数据写入缓冲区,并在缓冲区满或显式刷新时将数据写入底层的 io.Writer。
示例:
file, _ := os.Create("output.txt")
writer := bufio.NewWriter(file)
text := "Hello, World!"
writer.WriteString(text)
writer.Flush() // 刷新缓冲区,确保所有数据被写入底层的文件
file.Close()
bufio.Scanner
NewScanner() 函数用于创建一个缓冲读取器,它从指定的 io.Reader 中读取数据。
Scanner 类型提供了方便的方法来逐行或逐个词读取数据。
示例:
file, _ := os.Open("data.txt")
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
fmt.Println(line)
}
if err := scanner.Err(); err != nil {
fmt.Println("Error:", err)
}
Strconv
这个库就比较简单了,因为它主要就是用来我们的类型转换
string与int类型转换
Atoi()
Atoi()函数用于将字符串类型的整数转换为int类型 如果传入的字符串参数无法转换为int类型,就会返回错误。
s1 := "100"
i1, err := strconv.Atoi(s1)
if err != nil {
fmt.Println("can't convert to int")
} else {
fmt.Printf("type:%T value:%#v\n", i1, i1) //type:int value:100
}
Itoa()
Itoa()函数用于将int类型数据转换为对应的字符串表示
i2 := 200
s2 := strconv.Itoa(i2)
fmt.Printf("type:%T value:%#v\n", s2, s2) //type:string value:"200"
Parse系列函数
Parse类函数用于转换字符串为给定类型的值:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。
ParseBool()
ParseBool() 函数用于将字符串解析为布尔值。它接受一个字符串参数,该字符串必须是 “true”、“false”、“1” 或 “0”。
package main
import (
"fmt"
"strconv"
)
func main() {
str := "true"
boolValue, err := strconv.ParseBool(str)
if err != nil {
fmt.Println("解析错误:", err)
} else {
fmt.Println("解析的布尔值为:", boolValue)
}
}
下面的我就不举例子了,就和这个一样的
ParseFloat()
这个就是转为浮点数
str := "3.14"
floatValue, err := strconv.ParseFloat(str, 64)
第二个参数 64 指定浮点数的位数,这里解析为 float64。
ParseInt()
package main
import (
"fmt"
"strconv"
)
func main() {
str := "123"
intValue, err := strconv.ParseInt(str, 10, 64)
if err != nil {
fmt.Println("解析错误:", err)
} else {
fmt.Println("解析的整数为:", intValue)
}
}
可以选择进制和int类型
Format系列函数
Format就是格式化的意思
什么叫做格式化
比如我举bool这个类型的例子
我bool的表示方式可以是false,ture,1,0
但是格式化后我的1,0都用false和ture表示
…
Http和URL
Http其实是在net库中的其中之一
Http提供了我们http服务端和客户端的实现
然后在这里简单讲讲URl库在http服务发挥的作用
你可以使用url.Values来构建查询字符串,并使用url.Path和url.RawQuery来构建完整的URL
package main
import (
"fmt"
"net/url"
)
func main() {
// 创建一个url.Values实例
params := url.Values{}
params.Add("key1", "value1")
params.Add("key2", "value2")
// 使用Encode方法将其转换为查询字符串
queryStr := params.Encode()
fmt.Println(queryStr) // 输出: "key1=value1&key2=value2"
// 构建完整的URL
basePath := "https://example.com/path"
fullUrl := basePath + "?" + queryStr
fmt.Println(fullUrl) // 输出: "https://example.com/path?key1=value1&key2=value2"
}
看了这个例子应该能够明白
Http客户端
发送请求
http.Get(url string) (*http.Response, error): 发送一个GET请求到指定的URL。
http.NewRequest(method, url string, body io.Reader) (*http.Request, error): 创建一个新的HTTP请求。
http.Do(req *http.Request) (*http.Response, error): 执行一个HTTP请求,并返回响应。
处理响应
resp.Body: 响应体,可以使用
ioutil.ReadAll(resp.Body)来读取。
resp.Status: 响应的状态行(例如:“200 OK”)。
resp.Header: 响应的HTTP头。
设置请求头和客户端参数
req.Header.Set(key, value): 设置请求头的值。
req.URL.Path: 设置请求的URL路径。
req.URL.RawQuery: 设置请求的查询字符串。
get请求和响应
我直接举个例子,然后来讲解
package main
import (
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
func main() {
// 创建一个url.Values实例,设定立了我们查询的参数
params := url.Values{}
params.Add("key1", "value1")
params.Add("key2", "value2")
// 使用Encode方法将其转换为查询字符串
queryStr := params.Encode()
// 构建完整的URL
basePath := "https://example.com/path"
fullUrl := basePath + "?" + queryStr
// 发送GET请求
resp, err := http.Get(fullUrl)
if err != nil {
fmt.Println("Error making request:", err)
return
}
defer resp.Body.Close()
// 读取并打印响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return
}
// 打印响应体
fmt.Println("Response body:", string(body))
// 打印响应状态
fmt.Println("Response status:", resp.Status)
// 打印响应头
fmt.Println("Response headers:", resp.Header)
}
post请求和响应
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
// 创建表单数据
formData := url.Values{
"key1": {"value1"},
"key2": {"value2"},
}
// 创建请求体
body := bytes.NewBufferString(formData.Encode())
// 发送POST请求
resp, err := http.Post("http://example.com/resource", "application/x-www-form-urlencoded", body)//三个参数,第一个是请求的url,第二个是type,第三个是请求头,也就是我们的参数和参数值
if err != nil {
fmt.Println("请求失败:", err)
return
}
defer resp.Body.Close()
// 读取响应体
responseBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("读取响应失败:", err)
return
}
// 打印响应体
fmt.Println("Response body:", string(body))
// 打印响应状态
fmt.Println("Response status:", resp.Status)
// 打印响应头
fmt.Println("Response headers:", resp.Header)
}
服务端
对应的客户端写好了,思考我们怎么写服务端呢
无疑需要实现下面几个功能
启动服务器 – 接收请求 – 处理请求 – 返回处理结果
设置路由和处理函数
http.HandleFunc(pattern string, handler http.HandlerFunc): 注册一个路由和处理函数。
http.Handle(pattern string, handler http.Handler): 注册一个路由和处理器,适用于各种类型的HTTP处理函数。
启动服务器
http.ListenAndServe(addr string, handler http.Handler) error: 监听并服务指定的地址(如:“localhost:8080”)。
http.ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler) error: 类似于ListenAndServe,但用于HTTPS。
处理请求
中间件是在请求处理前后添加额外功能的函数。
http.HandlerFunc: 一个接受两个参数(http.ResponseWriter和http.Request)并返回一个http.Handler的函数。
实例分析
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/resource", func(w http.ResponseWriter, r *http.Request) {
// 接收请求
body, err := ioutil.ReadAll(r.Body)
defer r.Body.Close()
if err != nil {
http.Error(w, "Error reading request body", http.StatusInternalServerError)
return
}
//处理请求
fmt.Println("Received request with body:", string(body))
//返回结果
w.Write([]byte("OK"))
})
//启动服务器
fmt.Println("Starting server on port 8080")
http.ListenAndServe(":8080", nil)
}
看起来还是比较简单的
数据处理
我们知道交互的时候可不是数据原封不动的,一般都要转为其他的格式
常见的就是json,xml,二进制
JSON
编码
json使用go语言内置的encoding/json 标准库
编码json使用json.Marshal()函数可以对一组数据进行JSON格式的编码
package main
import (
"encoding/json"
"fmt"
"log"
)
// 定义一个结构体,用于表示一个人
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
}
func main() {
// 创建一个Person实例
p := Person{Name: "张三", Age: 30, Email: "zhangsan@example.com"}
// 使用json.Marshal对Person实例进行编码
data, err := json.Marshal(p)
if err != nil {
log.Fatal("JSON marshaling failed: ", err)
}
// 输出编码后的JSON字符串
fmt.Println(string(data))//{"name":"张三","age":30,"email":"zhangsan@example.com"}
}
解码
使用json.Unmarshal()函数可以对一组数据进行JSON格式的解码
package main
import (
"encoding/json"
"fmt"
"log"
)
// 定义一个结构体,用于表示一个人
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email"`
}
func main() {
// 假设我们有一个JSON格式的字符串
jsonData := `{"name":"张三","age":30,"email":"zhangsan@example.com"}`
// 创建一个Person实例,用于存储解码后的数据
var p Person
// 使用json.Unmarshal对JSON数据进行解码
err := json.Unmarshal([]byte(jsonData), &p)
if err != nil {
log.Fatal("JSON unmarshaling failed: ", err)
}
// 输出解码后的Person实例的字段
fmt.Printf("Name: %s\n", p.Name)
fmt.Printf("Age: %d\n", p.Age)
fmt.Printf("Email: %s\n", p.Email)
}
输出
Name: 张三
Age: 30
Email: zhangsan@example.com
XML
在Go语言中,处理XML数据同样简单,可以使用encoding/xml标准库来实现。这个库提供了Marshal和Unmarshal函数,用于XML数据的编码和解码。
XML编码(Marshal)
package main
import (
"encoding/xml"
"fmt"
"os"
)
// Person 结构体定义
type Person struct {
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email"`
}
func main() {
// 创建一个Person实例
p := Person{Name: "张三", Age: 30, Email: "zhangsan@example.com"}
// 使用xml.Marshal对Person实例进行编码
data, err := xml.Marshal(p)
if err != nil {
fmt.Println("XML marshaling failed:", err)
return
}
// 输出编码后的XML字符串
fmt.Println(string(data))
// 为了格式化输出,可以使用xml.MarshalIndent
data, err = xml.MarshalIndent(p, " ", " ")
if err != nil {
fmt.Println("XML marshaling failed:", err)
return
}
// 将格式化的XML输出到标准输出
fmt.Println(string(data))
}
XML解码(Unmarshal)
package main
import (
"encoding/xml"
"fmt"
"io/ioutil"
"os"
)
// Person 结构体定义
type Person struct {
Name string `xml:"name"`
Age int `xml:"age"`
Email string `xml:"email"`
}
func main() {
// 假设我们有一个XML格式的字符串
xmlData := `<Person><name>张三</name><age>30</age><email>zhangsan@example.com</email></Person>`
// 使用xml.Unmarshal对XML数据进行解码
var p Person
err := xml.Unmarshal([]byte(xmlData), &p)//接收两个变量,一个是xml数据但是要切片,一个是接收对象
if err != nil {
fmt.Println("XML unmarshaling failed:", err)
return
}
// 输出解码后的Person实例的字段
fmt.Printf("Name: %s\n", p.Name)
fmt.Printf("Age: %d\n", p.Age)
fmt.Printf("Email: %s\n", p.Email)
}
MSGPack
它相比于xml和json,更快,是一种高效的二进制序列化格式
但是需要安装
go get github.com/vmihailenco/msgpack/v5
package main
import (
"fmt"
"github.com/vmihailenco/msgpack/v5"
)
// Person 结构体定义
type Person struct {
Name string
Age int
Email string
}
func main() {
// 创建一个Person实例
p := Person{Name: "张三", Age: 30, Email: "zhangsan@example.com"}
// 使用msgpack.Marshal对Person实例进行编码
data, err := msgpack.Marshal(p)
if err != nil {
fmt.Println("MSGPack marshaling failed:", err)
return
}
// 使用msgpack.Unmarshal对MSGPack数据进行解码
var p2 Person
err = msgpack.Unmarshal(data, &p2)
if err != nil {
fmt.Println("MSGPack unmarshaling failed:", err)
return
}
// 输出解码后的Person实例的字段
fmt.Printf("Name: %s\n", p2.Name)
fmt.Printf("Age: %d\n", p2.Age)
fmt.Printf("Email: %s\n", p2.Email)
}
我们首先使用msgpack.Marshal()函数将Person实例编码为MessagePack格式的数据。然后,我们使用msgpack.Unmarshal()函数将这些数据解码回一个新的Person实例p2。msgpack.Unmarshal()函数接受两个参数:第一个是要解码的字节切片,第二个是一个指向要填充数据的变量的指针。