09-Go语言基础之标准库

fmt标准库

fmt包主要用于打印输出、获取输入两部分,如printf、scanf的格式化I/O函数。

打印输出

print相关

image-20230107154519911

Print系列函数用于将数据输出到、系统的标准输出;

Printf函数支持格式化字符串打印输出;

Println函数在打印内容结尾自动添加换行符;

package main

import "fmt"

func main() {
    fmt.Print("普通打印,没换行的。。")
    website := "www.yuchaoit.cn"
    fmt.Printf("于超老师博客网站:%s\n", website)
    fmt.Println("带着换行的打印 2")
    fmt.Println("哦 是吗?")
}

/*
普通打印,没换行的。。于超老师博客网站:www.yuchaoit.cn
带着换行的打印 2
哦 是吗?


*/

Sprint相关

image-20230108155010792

package main

import "fmt"

func main() {
    //Sprint系列函数是把传入的数据,返回成字符串类型
    s1 := fmt.Sprint(123456)
    fmt.Printf("s1类型:%T、值%#v\n", s1, s1)

    //Sprintf格式化字符串
    name := "于超"
    age := 18
    s2 := fmt.Sprintf("姓名:%v、年龄:%d\n", name, age)

    //Sprintln,返回字符串,带着换行\n
    s3 := fmt.Sprintln("于超老师666")

    fmt.Printf("s2值:%#v、类型:%T\n", s2, s2)
    fmt.Printf("s3值:%#v、类型:%T\n", s3, s3)
    print(s3, s2)
}

/*
➜  goStudy go run m1.go
s1类型:string、值"123456"
s2值:"姓名:于超、年龄:18\n"、类型:string
s3值:"于超老师666\n"、类型:string
于超老师666
姓名:于超、年龄:18

*/

通用格式化占位符

占位符 说明
%v 值的默认格式表示
%+v 类似%v,但输出结构体时会添加字段名
%#v 值的Go语法表示
%T 打印值的类型
%% 百分号

布尔型

占位符 说明
%t true或false

整型

占位符 说明
%b 表示为二进制
%c 该值对应的unicode码值
%d 表示为十进制
%o 表示为八进制
%x 表示为十六进制,使用a-f
%X 表示为十六进制,使用A-F
%U 表示为Unicode格式:U+1234,等价于”U+%04X”
%q 该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示

浮点数与复数

占位符 说明
%b 无小数部分、二进制指数的科学计数法,如-123456p-78
%e 科学计数法,如-1234.456e+78
%E 科学计数法,如-1234.456E+78
%f 有小数部分但无指数部分,如123.456
%F 等价于%f
%g 根据实际情况采用%e或%f格式(以获得更简洁、准确的输出)
%G 根据实际情况采用%E或%F格式(以获得更简洁、准确的输出)

字符串和[]byte

占位符 说明
%s 直接输出字符串或者[]byte
%q 该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示
%x 每个字节用两字符十六进制数表示(使用a-f
%X 每个字节用两字符十六进制数表示(使用A-F)

指针

占位符 说明
%p 表示为十六进制,并加上前导的0x

fmt包获取用户输入

image-20230108160140989

Go语言提供的接收用户输入有

fmt.Scan
fmt.Scanf
fmt.Scanln
三个函数

fmt.Scan

func Scan(a ...any) (n int, err error) {
    return Fscan(os.Stdin, a...)
}

Scan函数从标准输入扫描文本,读取由空白符分割的值,传递给本函数的参数,换行符就识别为空白符;
函数返回成功扫描的数据数量,以及可能发生的错误。

演示

package main

import "fmt"

func main() {
    //var (
    //    name string
    //    age  int
    //)
    //fmt.Print("请依次输入姓名、年龄:")
    //fmt.Scan(&name, &age)
    //fmt.Printf("以接收数据:姓名:%s、年龄:%d\n", name, age)

    //错误演示,不按要求输入
    var (
        v1 int
        v2 string
        v3 bool
    )
    fmt.Println("请依次输入,数字,字符串,布尔值。")
    nums, err := fmt.Scan(&v1, &v2, &v3)
    if err != nil {
        fmt.Println("出错了", err)
    }
    fmt.Printf("接收数据个数:%d、用户依次输入结果:%d、%s、%t\n", nums, v1, v2, v3)

}

fmt.Scanf

func Scanf(format string, a ...any) (n int, err error) {
    return Fscanf(os.Stdin, format, a...)
}

1. 该函数以空格作为输入数据的分隔符
2. Scanf限制了输入的数据格式

案例

package main

import "fmt"

func main() {
    var (
        name string
        age  int
    )
    fmt.Scanf("1:%s 2:%d", &name, &age)

    fmt.Printf("以接收数据:姓名:%s、年龄:%d\n", name, age)

}

/*
➜  goStudy go run m1.go
1:于超 2:18
以接收数据:姓名:于超、年龄:18

若不按该字符串格式输入,无法拿到数据
*/

Scanln和Scan区别

该函数类似于Scan、遇见换行时停止扫描,最后一个输入数据,必须有换行。

  • Scan函数以空白符作为数据分割(空格、换行)
  • Scanln扫描到换行、输入结束
package main

import "fmt"

func main() {
    var (
        name    string
        age     int
        married bool
    )
    fmt.Print("请依次输入姓名、年龄、已婚:")
    /*
        ➜  goStudy go run m1.go
        请依次输入姓名、年龄、已婚:于超 18
        true
        以接收数据:姓名:于超、年龄:18、已婚:true


    */
    //fmt.Scan(&name, &age, &married)

    /*
        Scanln遇见换行直接结束扫描
        ➜  goStudy go run m1.go
        请依次输入姓名、年龄、已婚:于超
        以接收数据:姓名:于超、年龄:0、已婚:false

    */
    fmt.Scanln(&name, &age, &married)

    fmt.Printf("以接收数据:姓名:%s、年龄:%d、已婚:%t\n", name, age, married)

}

Go文件操作

文件就是指计算机存储介质中的数据集合、如U盘、磁盘等;

一般是文本数据、图片、音视频等;

image-20230108175501454

os库文件操作

os.Stat()

package main

import (
    "fmt"
    "os"
)

func main() {

    fileInfo, err := os.Stat("./client.go")
    if err != nil {
        fmt.Println("err :", err)
        return
    }
    fmt.Printf("%T\n", fileInfo)
    //文件名
    fmt.Println(fileInfo.Name())
    //文件大小
    fmt.Println(fileInfo.Size())
    //是否是目录
    fmt.Println(fileInfo.IsDir())
    //修改时间
    fmt.Println(fileInfo.ModTime())
    //权限
    fmt.Println(fileInfo.Mode())
}

/*
➜  goStudy go run server.go
*os.fileStat
client.go
30
false
2023-01-16 17:56:36.306007232 +0800 CST
-rw-r--r--

*/

文件、目录操作

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

/*
1.路径查询
绝对路径 relative
相对路径 absolute

2.创建文件
os.MkDir() 一层目录
os.MkDirAll() 多层目录

3.创建文件,,默认0666权限
os.Create()

4.打开文件,获取文件对象,程序可以后续处理
os.Open(filename)
os.OpenFile(filename,mode,perm)

5.关闭文件:程序和文件之间的链接断开。
file.Close()

6.删除文件或目录:慎用,慎用,再慎用
os.Remove(),删除文件和空目录
os.RemoveAll(),删除所有
*/
func main() {
    //1.获取绝对路径路径
    file := "./client.go"
    file2 := "/Users/yuchao/goStudy/client.go"
    fmt.Println(filepath.Abs(file)) //Abs函数返回文件绝对路径
    fmt.Println(filepath.Abs(file2))

    //2.在go语言中操作文件路径主要使用 filepath 这个包,使用也比较简单,已经写在注释里了。
    pwd, _ := os.Getwd()
    fmt.Printf("2.当前代码路径:%s\n", pwd)

    //3.文件路径拼接
    newFile := filepath.Join(pwd, "a", "b.txt")
    fmt.Printf("3.拼接后文件路径:%s\n", newFile)

    //4.文件路径切割
    d1, f1 := filepath.Split(newFile)
    fmt.Printf("4.目录:%s、文件:%s\n", d1, f1)

    //5.获取文件后缀
    fmt.Printf("5.该文件后缀:%s\n", filepath.Ext(newFile))

    //6.判断文件是否在
    fileInfo, err := os.Stat(newFile)
    if err != nil {
        fmt.Println(err.Error())
        if os.IsNotExist(err) {
            fmt.Println("6. file:", f1, " not exist!")
        }
    } else {
        //判断路径是否为文件夹
        fmt.Println(fileInfo.IsDir())
        fmt.Println(!fileInfo.IsDir())
        fmt.Println(fileInfo.Name())

    }
    // 7.创建文件
    f, err := os.Create(newFile)
    defer f.Close()
    if err != nil {
        fmt.Println(err.Error())
        return
    } else {
        _, err = f.Write([]byte("www.yuchaoit.cn"))
    }

    //8.删除文件
    //err = os.RemoveAll(newFile)
    //if err != nil {
    //    fmt.Println(err.Error())
    //    return
    //}
    //fmt.Println(newFile, "已被删除。")
}

打开、关闭文件

标准库os库用于与操作系统交互。

1. os.Open()用于打开文件,返回文件*File以及err。
2. 调用close()方法关闭文件对象

func Open(name string) (*File, error) {
    return OpenFile(name, O_RDONLY, 0)
}

案例

package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("./toFile/hello.txt")
    if err != nil {
        fmt.Println("打开文件出错:", err)
        return
    }
    fmt.Printf("文件句柄类型:%T、值:%v\n", file, file)

    //务必记得关闭文件句柄,否则数据可能丢失,写入失败,重则大量浪费系统文件描述符
    // defer是关闭文件最好方式
    file.Close()

}

打开文件权限参数

打开标记:
O_RDONLY:只读模式(read-only)
O_WRONLY:只写模式(write-only)
O_RDWR:读写模式(read-write)
O_APPEND:追加模式(append)
O_CREATE:文件不存在就创建(create a new file if none exists.)
O_EXCL:与 O_CREATE 一起用,构成一个新建文件的功能,它要求文件必须不存在(used with O_CREATE, file must not exist)
O_SYNC:同步方式打开,即不使用缓存,直接写入硬盘
O_TRUNC:打开并清空文件
文件权限(unix权限位):只有在创建文件时才需要,不需要创建文件可以设置为 0。os库虽然提供常量,一般直接写数字,如0664。
如果你需要设置多个打开标记和unix权限位,需要使用位操作符"|"

os.Read()读取文件

文件对象,提供了Read()方法

func (f *File) Read(b []byte) (n int, err error)
接收字节切片,返回字节数,以及可能出错;
读取到文件结尾返回0或io.EOF。

基本读法

package main

import (
    "fmt"
    "os"
)

func main() {
    //默认不传参,只读打开
    file, err := os.Open("./toFile/hello.txt")
    //提前做好err判断,避免nil.Close()
    if err != nil {
        fmt.Println("打开文件出错:", err)
        return
    }
    //f有值之后,是需要关闭的,代码走到这里,defer关闭file
    defer file.Close()

    //读取文件数据,传入切片,一次性读取4k、2k、1k都是常见做法
    var data [4096]byte
    nums, err := file.Read(data[:])
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    //根据数据长度,截取元素即可
    fmt.Printf("File data >>:%s", data[:nums])

}

/*
    file.Read()方法读取数据
    接收字节切片,返回字节数,以及可能出错;
    读取到文件结尾返回0或io.EOF。
*/

循环读取

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    //默认不传参,只读打开
    file, err := os.Open("./toFile/hello.txt")
    //提前做好err判断,避免nil.Close()
    if err != nil {
        fmt.Println("打开文件出错:", err)
        return
    }
    //f有值之后,是需要关闭的,代码走到这里,defer关闭file
    defer file.Close()

    //读取文件数据,传入切片,一次性读取4k、2k、1k都是常见做法
    //文件数据太大怎么办?循环读取
    var data []byte
    var tmp = make([]byte, 128)
    for {
        //用tmp切片,循环取走文件数据,一次128字节
        nums, err := file.Read(tmp)
        //读取到文件结尾时,中断循环
        if err == io.EOF {
            fmt.Println("文件读完了")
            break
        }
        if err != nil {
            fmt.Println("Error:", err)
            return
        }
        //每次读取的128字节数据,加入data切片
        data = append(data, tmp[:nums]...)
    }
    fmt.Printf("%s", data)

}

/*
    file.Read()方法读取数据
    接收字节切片,返回字节数,以及可能出错;
    读取到文件结尾返回0或io.EOF。
*/

基本写入

package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.OpenFile("toFile/t1.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("open file failed, err:", err)
        return
    }
    defer file.Close()

    //str := "www.yuchaoit.cn"
    //file.Write([]byte(str)) //写入字节切片数据
    file.WriteString("超哥带你学golang\n") //直接写入字符串数据
}

bufio库

标准库bufio封装了更完善读取文件的操作,如缓冲区,更完善、优雅的让你读写文件。

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

func main() {
    //默认不传参,只读打开
    file, err := os.Open("./toFile/hello.txt")
    //提前做好err判断,避免nil.Close()
    if err != nil {
        fmt.Println("打开文件出错:", err)
        return
    }
    //f有值之后,是需要关闭的,代码走到这里,defer关闭file
    defer file.Close()

    //使用bufio包读文件
    reader := bufio.NewReader(file)
    //循环通过reader、按行读数据即可
    for {
        line, err := reader.ReadString('\n') //以换行符,表一行结束
        if err == io.EOF {
            fmt.Println(line) //最后一行
            fmt.Println("文件读完了")
            break
        }
        fmt.Print(line) //循环打印行
    }
}

写入数据

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    file, err := os.OpenFile("t1.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0666)
    if err != nil {
        fmt.Println("open file failed, err:", err)
        return
    }
    defer file.Close()
    //bufio包写入文件数据
    writer := bufio.NewWriter(file)
    for i := 0; i < 10; i++ {
        writer.WriteString("超哥带你学golang\n") //将数据先写入缓存
    }
    writer.Flush() //将缓存中的内容写入文件
}

ioutil库(弃用)

io/ioutil库一般用于读小文件,只需要传入文件名,更方便使用,但是大文件依然建议用bufio库读取

package main

import (
    "fmt"
    "os"
)

func main() {
    //data, err := ioutil.ReadFile("./toFile/hello.txt")
    // Go 1.16版本之后的优化
    data, err := os.ReadFile("./toFile/hello.txt")
    if err != nil {
        fmt.Println("Error:", err)
    }
    fmt.Println(string(data))
}

写入数据

package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.OpenFile("toFile/t1.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if err != nil {
        fmt.Println("open file failed, err:", err)
        return
    }
    defer file.Close()

    //str := "www.yuchaoit.cn"
    //file.Write([]byte(str)) //写入字节切片数据
    file.WriteString("超哥带你学golang\n") //直接写入字符串数据
}

开发一个cat命令

package main

import (
    "bufio"
    "flag"
    "fmt"
    "io"
    "os"
)

// cat函数开发
// 传入文件名
func cat(r *bufio.Reader) {
    for {
        buf, err := r.ReadBytes('\n')
        if err == io.EOF {
            //打印最后一行的内容
            fmt.Fprintf(os.Stdout, "%s", buf)
            break
        }
        fmt.Fprintf(os.Stdout, "%s", buf)
    }
}

func main() {
    //cat语法 cat 1.log 2.log 3.log 打印出3个文件的所有内容
    //解析命令函数
    flag.Parse()
    // cat命令不传入参数,直接从 stdin获取数据
    if flag.NArg() == 0 {
        cat(bufio.NewReader(os.Stdin)) //从标准输入,传入字符串数据
    }
    //循环cat每一个文件
    for i := 0; i < flag.NArg(); i++ {
        //打开文件
        f, err := os.Open(flag.Arg(i))
        if err != nil {
            //打印报错到终端
            fmt.Fprintf(os.Stdout, "reading from %s failed,err:%v\n", flag.Arg(i), err)
            continue //跳过该文件继续下一个
        }
        cat(bufio.NewReader(f))
    }

}

io包

I/O操作也叫输入输出操作。其中I是指Input,O是指Output,用于读或者写数据的,有些语言中也叫流操作,是指数据通信的通道。

Golang 标准库对 IO 的抽象非常精巧,各个组件可以随意组合,可以作为接口设计的典范。

io包中提供I/O原始操作的一系列接口。

它主要包装了一些已有的实现,如 os 包中的那些,并将这些抽象成为实用性的功能和一些其他相关的接口。

由于这些接口和原始的操作以不同的实现包装了低级操作,客户不应假定它们对于并行执行是安全的。

在io包中最重要的是两个接口:Reader和Writer接口,首先来介绍这两个接口.

Reader接口的定义,Read()方法用于读取数据。

type Reader interface {
        Read(p []byte) (n int, err error)
}

Writer接口的定义,Write()方法用于写出数据。

type Writer interface {
        Write(p []byte) (n int, err error)
}

Seeker接口的定义,封装了基本的 Seek 方法。

type Seeker interface {
        Seek(offset int64, whence int) (int64, error)
}

ReaderFrom接口的定义,封装了基本的 ReadFrom 方法。

type ReaderFrom interface {
        ReadFrom(r Reader) (n int64, err error)
}

file包

file类是在os包中的,封装了底层的文件描述符和相关信息,同时封装了Read和Write的实现。


func (f *File) Read(b []byte) (n int, err error)
//Read方法从f中读取最多len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。文件终止标志是读取0个字节且返回值err为io.EOF。

func (f *File) ReadAt(b []byte, off int64) (n int, err error)
//ReadAt从指定的位置(相对于文件开始位置)读取len(b)字节数据并写入b。它返回读取的字节数和可能遇到的任何错误。当n<len(b)时,本方法总是会返回错误;如果是因为到达文件结尾,返回值err会是io.EOF。

func (f *File) Write(b []byte) (n int, err error)
//Write向文件中写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

func (f *File) WriteString(s string) (ret int, err error)
//WriteString类似Write,但接受一个字符串参数。

func (f *File) WriteAt(b []byte, off int64) (n int, err error)
//WriteAt在指定的位置(相对于文件开始位置)写入len(b)字节数据。它返回写入的字节数和可能遇到的任何错误。如果返回值n!=len(b),本方法会返回一个非nil的错误。

func (f *File) Seek(offset int64, whence int) (ret int64, err error)
//Seek设置下一次读/写的位置。offset为相对偏移量,而whence决定相对位置:0为相对文件开头,1为相对当前位置,2为相对文件结尾。它返回新的偏移量(相对开头)和可能的错误。

func (f *File) Sync() (err error)
//Sync递交文件的当前内容进行稳定的存储。一般来说,这表示将文件系统的最近写入的数据在内存中的拷贝刷新到硬盘中稳定保存。

io包实战

package main

import (
    "fmt"
    "io"
    "os"
)

func main() {
    //1.打开文件,程序可以操作file了
    fileName := "./a/b.txt"
    file, err := os.Open(fileName)
    if err != nil {
        fmt.Println("err:", err)
        return
    }
    //2.关闭文件
    defer file.Close()

    //3.读数据,传入字节切片
    data := make([]byte, 6) //一次性读取6个字节

    /*
        //4.读取1
        fmt.Println("-----第一次------")
        nums, err := file.Read(data)
        fmt.Println(err)
        fmt.Println(nums)
        fmt.Println(data)
        fmt.Println(string(data))

        fmt.Println("----第二次-------")
        //5.第二次读取
        nums, err = file.Read(data)
        fmt.Println(err)
        fmt.Println(nums)
        fmt.Println(data)
        fmt.Println(string(data))

        fmt.Println("----第三次-------")
        //6.第3次读取
        nums, err = file.Read(data)
        fmt.Println(err)
        fmt.Println(nums)
        fmt.Println(data)
        fmt.Println(string(data))

        fmt.Println("----第四次-------")
        //6.第4次读取,可以看到,如果文件读取结束后,到结尾会出现EOF错误,得做好异常处理
        nums, err = file.Read(data)
        if nums == 0 || err == io.EOF {
            fmt.Println("文件已全部读完,结束读取。")
            return
        }
        fmt.Println(err)
        fmt.Println(nums)
        fmt.Println(data)
        fmt.Println(string(data))


    */

    //7.改进为for循环读取
    n := -1
    for {
        n, err = file.Read(data)
        if n == 0 || err == io.EOF {
            fmt.Println("文件已全部读完,结束读取。")
            break
        }
        fmt.Println(string(data[:n]))
    }
}

io.Copy()复制

package main

import (
    "fmt"
    "io"
    "os"
)

//io.Copy函数

func copyFile(src, dest string) (int64, error) {
    file1, err := os.Open(src)
    if err != nil {
        return 0, err
    }
    file2, err := os.OpenFile(dest, os.O_WRONLY|os.O_CREATE, os.ModePerm)
    if err != nil {
        return 0, err
    }
    defer file1.Close()
    defer file2.Close()

    return io.Copy(file2, file1) //读出来file1的数据,交给file2
}
func main() {
    n, err := copyFile("./a/b.txt", "./a/new_b.txt")
    fmt.Println(n, err)
    if n == 0 || err != nil {
        fmt.Println("文件拷贝出错")
        return
    }
}

文件夹递归

模拟tree命令,主要学习os.ReadDir函数

package main

import (
    "fmt"
    "log"
    "os"
)

// 模拟开发一个简单的tree命令,递归显示目录
func myTree(dirname string, level int) {
    //记录递归层数level、查询的目录名
    //循环拼接每一层前面的层级符号
    s := "|--"
    for i := 0; i < level; i++ {
        s = "|  " + s
    }
    //从 Go 1.16 开始,os.ReadDir 是更有效和正确的选择: 替换了ioutil.ReadDir
    //返回文件指针切片
    fileInfos, err := os.ReadDir(dirname)
    if err != nil {
        log.Fatalln(err)
    }

    for _, fi := range fileInfos {
        filename := dirname + "/" + fi.Name()
        fmt.Printf("%s%s\n", s, filename)
        if fi.IsDir() {
            //继续遍历fi这个目录,每次递归+1,拼接一层目录
            myTree(filename, level+1)
        }
    }

}
func main() {
    myTree(".", 0)
}

Time包

时间、日期是经常要处理且重要的,如日志记录等。

Go语言提供了time包显示,计算时间,并且time包才用的是公历。

时间类型time.Time

package main

import (
    "fmt"
    "time"
)

func main() {
    now := time.Now()
    fmt.Printf("当前时间:%v、类型:%T\n", now, now) //当前时间:2023-01-12 15:25:19.500149 +0800 CST m=+0.000084459 类型:time.Time

    //类型:time.Time 是一个结构体,且绑定了方法
    year := now.Year()
    month := now.Month()
    day := now.Day()
    hour := now.Hour()
    min := now.Minute()
    second := now.Second()
    fmt.Printf("年月日 时分秒:%d-%d-%d %d:%d:%d\n", year, month, day, hour, min, second)
}

Unix Time

package main

import (
    "fmt"
    "time"
)

/*
    >>> 1673509968/60/60/24/365
    53.066652968036536  大约过了53年
    >>> 2023-1970
    53

2023-01-12 15:55:16.591408 +0800 CST m=+0.000094043
1673510116
1673510116591
1673510116591408
1673510116591408000

*/

func unixTime() {
    //Unix Time是自1970年1月1日 00:00:00 UTC 至当前时间经过的总秒数。
    now := time.Now() //2023-01-12 15:51:37.819949 +0800 CST m=+0.000080835 中国标准时间
    fmt.Println(now)
    //获取时间戳,过了多少秒
    timestamp := now.Unix()
    //获取毫秒时间戳
    milli := now.UnixMilli()
    //微妙、纳秒
    micro := now.UnixMicro()
    nano := now.UnixNano()
    fmt.Println(timestamp)
    fmt.Println(milli)
    fmt.Println(micro)
    fmt.Println(nano)

}

func main() {
    unixTime()

}

时间计算

image-20230112155807093

package main

import (
    "fmt"
    "time"
)

func unixTime() {
    //Unix Time是自1970年1月1日 00:00:00 UTC 至当前时间经过的总秒数。
    now := time.Now() //2023-01-12 15:51:37.819949 +0800 CST m=+0.000080835 中国标准时间
    fmt.Println(now)
    //获取时间戳,过了多少秒
    timestamp := now.Unix()
    //获取毫秒时间戳
    milli := now.UnixMilli()
    //微妙、纳秒
    micro := now.UnixMicro()
    nano := now.UnixNano()
    fmt.Println(timestamp)
    fmt.Println(milli)
    fmt.Println(micro)
    fmt.Println(nano)

}

// 时间计算
func timeCalc() {
    now := time.Now()
    onehourlater := now.Add(time.Hour)
    //Sub()方法返回一个time.Duration类型,表示是两个时间点经过的时间,是纳秒单位
    /*
        const (
            Nanosecond  Duration = 1
            Microsecond          = 1000 * Nanosecond
            Millisecond          = 1000 * Microsecond
            Second               = 1000 * Millisecond
            Minute               = 60 * Second
            Hour                 = 60 * Minute
        )
    */
    fmt.Printf("这会%v点、一小时之后%v点\n", now.Hour(), onehourlater.Hour())
    //间隔时间处理,time.Duration 期间
    d := onehourlater.Sub(now)
    fmt.Printf("间隔了%d纳秒、类型:%T,换算是%d小时。\n", d, d, d/1000/1000/1000/60/60)

}
func main() {
    //unixTime()
    timeCalc()

}

定时器

func tickDemo() {
    ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器
    //每秒都会执行的任务
    for t := range ticker {
        fmt.Printf("当前时间:%v,超哥带你学golang,www.yuchaoit.cn\n", t.Format("2006-01-02 15:04:05.000"))
    }
}

时间格式化

image-20230112163140952


image-20230112163304411

Go语言的时间格式化有点特殊,使用了一个固定时间字符串去格式化

2006-01-02 15:04:05.000(记忆口诀为2006 1 2 3 4 5)。

2006:年(Y)
01:月(m)
02:日(d)
15:时(H)
04:分(M)
05:秒(S)

实践

package main

import (
    "fmt"
    "time"
)

func unixTime() {
    //Unix Time是自1970年1月1日 00:00:00 UTC 至当前时间经过的总秒数。
    now := time.Now() //2023-01-12 15:51:37.819949 +0800 CST m=+0.000080835 中国标准时间
    fmt.Println(now)
    //获取时间戳,过了多少秒
    timestamp := now.Unix()
    //获取毫秒时间戳
    milli := now.UnixMilli()
    //微妙、纳秒
    micro := now.UnixMicro()
    nano := now.UnixNano()
    fmt.Println(timestamp)
    fmt.Println(milli)
    fmt.Println(micro)
    fmt.Println(nano)

}

// 时间计算
func timeCalc() {
    now := time.Now()
    onehourlater := now.Add(time.Hour)
    //Sub()方法返回一个time.Duration类型,表示是两个时间点经过的时间,是纳秒单位
    /*
        const (
            Nanosecond  Duration = 1
            Microsecond          = 1000 * Nanosecond
            Millisecond          = 1000 * Microsecond
            Second               = 1000 * Millisecond
            Minute               = 60 * Second
            Hour                 = 60 * Minute
        )
    */
    fmt.Printf("这会%v点、一小时之后%v点\n", now.Hour(), onehourlater.Hour())
    //间隔时间处理,time.Duration 期间
    d := onehourlater.Sub(now)
    fmt.Printf("间隔了%d纳秒、类型:%T,换算是%d小时。\n", d, d, d/1000/1000/1000/60/60)

}

func tickDemo() {
    ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器
    //每秒都会执行的任务
    for t := range ticker {
        fmt.Printf("当前时间:%v,超哥带你学golang,www.yuchaoit.cn\n", t.Format("2006-01-02 15:04:05.000"))
    }
}

//时间格式化

// formatDemo 时间格式化
func formatDemo() {
    now := time.Now()
    // 格式化的模板为 2006-01-02 15:04:05

    // 24小时制
    fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan")) //固定的时间格式
    // 12小时制,技巧就是多一个PM
    // fmt.Println(now.Format("Y.m.d H:M:S.000 PM Mon Jan"))
    fmt.Println(now.Format("2006.01.02 03:04:05.000 PM Mon Jan"))

    // 小数点后写0,因为有3个0所以格式化输出的结果也保留3位小数
    fmt.Println(now.Format("2006/01/02 15:04:05.000"))
    // 小数点后写9,会省略末尾可能出现的0
    fmt.Println(now.Format("2006/01/02 15:04:05.999"))

    // 只格式化时分秒部分
    fmt.Println(now.Format("15:04:05"))
    // 只格式化日期部分
    fmt.Println(now.Format("2006.01.02"))
}

/*
➜  learn_go_module go run main.go
        2023-01-12 16:29:03.978 Thu Jan
        2023.01.12 04:29:03.978 PM Thu Jan
        2023/01/12 16:29:03.978
        2023/01/12 16:29:03.978
        16:29:03
        2023.01.12
*/
func main() {
    //unixTime()
    //timeCalc()
    //tickDemo()
    formatDemo()
}
Copyright © www.yuchaoit.cn 2025 all right reserved,powered by Gitbook作者:于超 2023-01-28 11:13:33

results matching ""

    No results matching ""