fmt库
输出
func TestPrint(t *testing.T) {
fmt.Print("我是控制台输出,不带换行\n")
fmt.Println("我是控制台输出,带换行", "第二个", 5555)
fmt.Printf("我是控制台输出, %s 占位符", "张三")
}
输出:
我是控制台输出,不带换行
我是控制台输出,带换行 第二个 5555
我是控制台输出, 张三 占位符
注意点
- Print输出不带换行
- Println输出带换行
- Printf为格式化输出
占位符
通用占位符
- %v 值的默认格式表示
- %+v 类似%v,但输出结构体时会添加字段名
- %#v 值的Go语法表示,+包名+结构体名+字段名
- %T 打印值的类型
- %% 打印百分号
type User struct {
Id int64
}
func TestPrintf1(t *testing.T) {
user := &User{Id: 1}
fmt.Printf("%v\n", user)
fmt.Printf("%+v\n", user)
fmt.Printf("%#v\n", user)
fmt.Printf("%T\n", user)
fmt.Printf("%%\n")
}
输出:
&{1}
&{Id:1}
&fmt_test.User{Id:1}
*fmt_test.User
%
注意点
- %+v会在输出结构体时输出字段名
- %#v会输出包名+结构体名+字段名
布尔类型占位符
func TestPrintf2(t *testing.T) {
fmt.Printf("%t\n", true)
}
注意点
布尔类型的占位符为%t
整型占位符
func TestPrintf3(t *testing.T) {
n := 180
fmt.Printf("%b\n", n) // 二进制表示
fmt.Printf("%c\n", n) // 该值对应unicode的表示,即字符的表示
fmt.Printf("%d\n", n) // 十进制表示
fmt.Printf("%o\n", n) // 八进制表示
fmt.Printf("%x\n", n) // 十六进制小写表示
fmt.Printf("%X\n", n) // 十六进制大写表示
fmt.Printf("%U\n", n) // 加Unicode前置Unicode格式表示
a := 96
fmt.Printf("%q\n", a) // 该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
fmt.Printf("%q\n", 0x4E2D)
}
输出:
10110100
´
180
264
b4
B4
U+00B4
'`'
'中'
注意点
- %b为转换为二进制输出的占位符
- %c是转换为对应的unicode字符输出
- %d是十进制表示
- %o是八进制表示
- %x是十六进制的小写表示
- %X是十六进制的大写表示
浮点数与复数占位符
- %b 无小数部分、二进制指数的科学计数法,如-123456p-78
- %e 科学计数法,如-1234.456e+78
- %E 科学计数法,如-1234.456E+78
- %f 有小数部分但无指数部分,如123.456
- %F 等价于%f
- %g 根据实际情况采用%e或%f格式(以获得更简洁、准确的输出)
- %G 根据实际情况采用%E或%F格式(以获得更简洁、准确的输出)
func TestPrintf4(t *testing.T) {
f := 18.54
fmt.Printf("%b\n", f)
fmt.Printf("%e\n", f)
fmt.Printf("%E\n", f)
fmt.Printf("%f\n", f)
fmt.Printf("%F\n", f)
fmt.Printf("%g\n", f)
fmt.Printf("%G\n", f)
}
输出:
5218546068215562p-48
1.854000e+01
1.854000E+01
18.540000
18.540000
18.54
18.54
字符串与byte数组占位符
- %s 直接输出字符串或者[]byte
- %q 该值对应的双引号括起来的go语法字符串字面值,必要时会采用安全的转义表示
- %x 每个字节用两字符十六进制数表示(使用a-f
- %X 每个字节用两字符十六进制数表示(使用A-F)
func TestPrintf5(t *testing.T) {
s := "我是字符串"
b := []byte{65, 66, 67}
fmt.Printf("%s\n", s)
fmt.Printf("%s\n", b)
fmt.Printf("%q\n", s)
fmt.Printf("%x\n", s)
fmt.Printf("%X\n", s)
}
输出:
我是字符串
ABC
"我是字符串"
e68891e698afe5ad97e7aca6e4b8b2
E68891E698AFE5AD97E7ACA6E4B8B2
宽度标识符
-
宽度通过一个紧跟在百分号后面的十进制数指定,如果未指定宽度,则表示值时除必需之外不作填充。
-
精度通过(可选的)宽度后跟点号后跟的十进制数指定。如果未指定精度,会使用默认精度;如果点号后没有跟数字,表示精度为0。
-
%f 默认宽度,默认精度
-
%10f 宽度9,默认精度
-
%.2f 默认宽度,精度2(会四舍五入)
-
%10.2f 宽度9,精度2
-
%10.f 宽度9,精度0
func TestPrintf6(t *testing.T) {
n := 13.14
fmt.Printf("%f\n", n)
fmt.Printf("%10f\n", n)
fmt.Printf("%10s\n", "我是字符串")
fmt.Printf("%.2f\n", n)
fmt.Printf("%10.2f\n", n)
fmt.Printf("%10.f\n", n)
}
输出:
13.140000
13.140000
我是字符串
13.14
13.14
13
一个重要的内容:文件权限
- 对于一个perm为0644时,其中0表示8进制 644表示权限 os.FileMode(0777).String()进行打印
-
- rwx rwx rwx -表示普通文件
- r表示可读
- w表示可写
- x表示可执行
- 第1位:文件属性,一般常用的是"-",表示是普通文件;"d"表示是一个目录。
- 第2~4位:文件所有者的权限rwx (可读/可写/可执行)。
- 第5~7位:文件所属用户组的权限rwx (可读/可写/可执行)。
- 第8~10位:其他人的权限rwx (可读/可写/可执行)。
- 在golang中,可以使用os.FileMode(perm).String()来查看权限标识:
- os.FileMode(0777).String() //返回 -rwxrwxrwx 111 111 111
- os.FileMode(0666).String() //返回 -rw-rw-rw- 110 110 110
- os.FileMode(0644).String() //返回 -rw-r--r--
- 0777表示:创建了一个普通文件,所有人拥有所有的读、写、执行权限
- 0666表示:创建了一个普通文件,所有人拥有对该文件的读、写权限,但是都不可执行
- 0644表示:创建了一个普通文件,文件所有者对该文件有读写权限,用户组和其他人只有读权限,都没有执行权限
Fprint
go源码
func Fprint(w io.Writer, a ...any) (n int, err error) {
p := newPrinter()
p.doPrint(a)
n, err = w.Write(p.buf)
p.free()
return
}
func Fprintf(w io.Writer, format string, a ...any) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n, err = w.Write(p.buf)
p.free()
return
}
func Fprintln(w io.Writer, a ...any) (n int, err error) {
p := newPrinter()
p.doPrintln(a)
n, err = w.Write(p.buf)
p.free()
return
}
`n`是写入的字节数量,`err`是返回的错误
一般用于写文件时,追加写入。
func TestFPrint(t *testing.T) {
fmt.Fprintln(os.Stdout, "向标准输出写入字符串")
}
func TestFPrint1(t *testing.T) {
file, _ := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
fmt.Fprintln(file, "追加写入")
file.Close()
}
Sprint
把传入的数据生成,并返回一个字符串。
常用于解决字符串不能拼接非字符串类型的数据。
func TestSprint(t *testing.T) {
host := "localhost"
port := 6379
// 解决字符串不能拼接非字符串类型的数据
addr := fmt.Sprintf("%s:%d", host, port)
fmt.Println(addr)
}
Errorf
根据format参数生成格式化字符串并返回一个包含该字符串的错误。
用于自定义错误信息。
func TestErrorf(t *testing.T) {
err := fmt.Errorf("用户名格式不正确: %s", "哈哈")
if err != nil {
panic(err)
}
}
输入
Scan
go源码
func Scan(a ...any) (n int, err error) {
return Fscan(os.Stdin, a...)
}
从标准输入扫描文本,读取由空白符分隔的值保存到传递给本函数的参数中,换行符视为空白符。
本函数返回成功扫描的数据个数(n)和遇到的任何错误(error)。
Scanf
go源码
func Scanf(format string, a ...any) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
实际使用的是Fscanf
以format定义的格式来进行输入
func main() {
var (
name string
age int
married bool
)
fmt.Scanf("1:%s 2:%d 3:%t", &name, &age, &married)
fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
}
Scanln
go源码
func Scanln(a ...any) (n int, err error) {
return Fscanln(os.Stdin, a...)
}
func main() {
var (
name string
age int
married bool
)
fmt.Scanln(&name, &age, &married)
fmt.Printf("扫描结果 name:%s age:%d married:%t \n", name, age, married)
}
遇到回车就结束扫描。
Fsanf
go源码
func Fscanf(r io.Reader, format string, a ...any) (n int, err error) {
s, old := newScanState(r, false, false)
n, err = s.doScanf(format, a)
s.free(old)
return
}
func Fscan(r io.Reader, a ...any) (n int, err error) {
s, old := newScanState(r, true, false)
n, err = s.doScan(a)
s.free(old)
return
}
func Fscanln(r io.Reader, a ...any) (n int, err error) {
s, old := newScanState(r, false, true)
n, err = s.doScan(a)
s.free(old)
return
}
将内容从一个io.Reader接口类型的变量r中读取出来,将连续的以空格分隔的值存储到由格式确定的连续的参数中。
- r io.Reader:此参数包含扫描的指定文本。
- format string:此参数包含用于接收元素的不同格式。
- a …any:此参数是每个元素的指定变量。
返回值:它返回成功解析的项目数和错误。
os库
关于权限的重要常量
go中包含了很多常量,用于在os操作时设置文件的权限与进行操作。
const (
// Exactly one of O_RDONLY, O_WRONLY, or O_RDWR must be specified.
O_RDONLY int = syscall.O_RDONLY // open the file read-only.
O_WRONLY int = syscall.O_WRONLY // open the file write-only.
O_RDWR int = syscall.O_RDWR // open the file read-write.
// The remaining values may be or'ed in to control behavior.
O_APPEND int = syscall.O_APPEND // append data to the file when writing.
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist.
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.
)
os.Create - 创建文件
// 创建文件
func TestCreate(t *testing.T) {
file, err := os.Create("a.txt")
if err != nil {
panic(err)
}
defer file.Close()
}
os.Mkdir - 创建单个目录
参数为目录名以及权限。
// 创建单个目录
func TestMkdir(t *testing.T) {
err := os.Mkdir("dir1", os.ModePerm)
if err != nil {
panic(err)
}
}
os.MkdirAll - 创建多级目录
func TestMkdirAll(t *testing.T) {
err := os.MkdirAll("dir1/a/b", os.ModePerm)
if err != nil {
panic(err)
}
}
os.Remove - 删除一个文件或目录
// 删除一个文件或目录
func TestRemove(t *testing.T) {
err := os.Remove("dir1/a/b")
if err != nil {
panic(err)
}
}
os.RemoveAll - 删除整个目录
// 删除整个目录
func TestRemoveAll(t *testing.T) {
err := os.RemoveAll("dir1")
if err != nil {
panic(err)
}
}
os.Getwd - 获取工作目录
获取工作目录
func TestGetwd(t *testing.T) {
dir, err := os.Getwd()
if err != nil {
panic(err)
} else {
fmt.Print(dir)
}
}
os.Chdir - 修改工作目录
// 修改工作目录
func TestChdir(t *testing.T) {
err := os.Chdir("")
if err != nil {
panic(err)
}
}
os.TempDir - 获取临时目录
获取临时目录可以在其中存一些缓存或者中间值。
// 获取临时目录
func TestTempDir(t *testing.T) {
tempDir := os.TempDir()
fmt.Println(tempDir)
}
os.Rename - 重命名文件
// 重命名文件
func TestRename(t *testing.T) {
err := os.Rename("a.txt", "text1.txt")
if err != nil {
fmt.Println(err)
}
}
os.Chmod - 修改文件的权限
这个似乎得跑在linux上。
// 修改文件的权限
func TestChmod(t *testing.T) {
//err := os.Chmod("text1.txt", 0666)
}
os.Chown - 改变文件的所有者
这个似乎也得跑在linux上。
// 改变文件的所有者
func TestChown(t *testing.T) {
err := os.Chown("a.txt", 10, 100)
if err != nil {
panic(err)
}
}
进程相关
func osInfo() {
// 获取当前正在运行的进程id
fmt.Println("-----------------")
fmt.Printf("os.Getpid(): %v\n", os.Getpid())
// 父id
fmt.Printf("os.Getppid: %v\n", os.Getppid())
// 设置新进程的属性
attr := &os.ProcAttr{
// files指定新进程继承的活动文件对象
// 前三个分别为,标准输入、标准输出、标准错误输出
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
// 新进程的环境变量
Env: os.Environ(),
}
// 开启一个新进程
p, err := os.StartProcess("C:\Program Files (x86)\Notepad++\notepad++.exe",
[]string{"C:\Program Files (x86)\Notepad++\notepad++.exe"}, attr)
if err != nil {
panic(err)
}
fmt.Println(p)
fmt.Println("进程ID: ", p.Pid)
// 通过进程ID查找进程
p2, _ := os.FindProcess(p.Pid)
fmt.Println(p2)
// 等待10s,执行函数
time.AfterFunc(time.Second*10, func() {
// 向p进程发出退出信号
p.Signal(os.Kill)
})
// 等待进程p的退出,返回进程状态
ps, _ := p.Wait()
fmt.Println(ps.String())
}
注意点
- os.Getpid - 获取当前进程的pid
- os.Getppid - 获取当前进程的父进程的pid
- os.ProcAttr结构体的字段有Files和Env
- Files: Files指定新进程继承的活动文件对象 前三个分别为,标准输入、标准输出、标准错误输出
- Env: 新进程的环境变量
- os.StartProcess - 开启新进程,要传入进程的路径、字符串路径以及属性
- os.FindProcess - 通过pid查找进程
信号量
信号量可以帮助解决开启多个阻塞操作的问题。
type MyHandler struct {
}
func (m MyHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
//TODO implement me
panic("implement me")
}
func a() {
http.ListenAndServe(":8088", &MyHandler{})
}
func b() {
http.ListenAndServe(":8089", &MyHandler{})
}
func main() {
// 实现开启多个阻塞操作
go a()
go b()
ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, os.Kill)
c := <-ch
fmt.Println(c)
}
- signal.Notify - 传入的是管道,和终止的条件
文件相关
读取文件信息 - Stat
读取文件的信息
func fileStat() {
f, err := os.OpenFile("text1.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
fileInfo, err := f.Stat()
if err != nil {
panic(err)
}
fmt.Printf("FileInfo:%v", fileInfo)
}
信息包括这些字段:
type FileInfo interface {
Name() string // base name of the file
Size() int64 // length in bytes for regular files; system-dependent for others
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
Sys() any // underlying data source (can return nil)
}
读取文件内容 - Read
可在创建byte切片时设定一次性读入的长度,并append给body,body存入每次读入的内容。
func fileRead() {
f, err := os.OpenFile("text1.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
var body []byte
for {
buf := make([]byte, 4)
n, err := f.Read(buf)
if err == io.EOF { // 读完了
break
}
body = append(body, buf[:n]...)
}
fmt.Printf("Read Content:%v", body)
}
从指定位置读取文件内容 - ReadAt
从指定的位置开始读。
func fileReadAt() {
f, err := os.OpenFile("text1.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
buf := make([]byte, 5) // 读5个
n, err := f.ReadAt(buf, 6) // 从第六位开始读
fmt.Printf("Read Content:%v", buf[:n])
}
读取目录 - ReadDir
读取目录并返回排好序的文件以及子目录名切片。
dirs, err := f.ReadDir(-1) // -1代表读取所有
for _, v := range dirs {
}
设置读/写位置 - Seek
- seek设置下一次读/写的位置,offset为相对偏移量,而whence决定相对位置,0位相对文件开头,1为相对当前位置,2位相对文件结尾
- 它返回新的偏移量(相对开头)和可能的错误
func FileSeek() {
f, err := os.OpenFile("text1.txt", os.O_RDWR|os.O_CREATE, 0755)
if err != nil {
panic(err)
}
defer f.Close()
f.Seek(3, 0)
buf := make([]byte, 10)
n, _ := f.Read(buf)
fmt.Printf("读取内容:%s\n", buf[:n])
}
文件写入 - Write与WriteString
- Write向文件中写入len(b)字节数据,它返回写入的字节数和可能遇到的任何错误,如果返回值n!=len(b),本方法会返回一个非nil的错误
- WriteString和Write类似,但可以直接写入字符串,更方便些。
func fileWrite() {
f, err := os.OpenFile("text1.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
panic(err)
}
defer f.Close()
_, err1 := f.Write([]byte("hello\n"))
if err1 != nil {
panic(err1)
}
f.WriteString("world!\n")
}
指定位置写入 - WriteAt
从某个位置开始写入,注意写入的位置如果有原内容则会覆盖原内容。
func fileWriteAt() {
f, err := os.OpenFile("text1.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
panic(err)
}
defer f.Close()
_, err = f.WriteAt([]byte("GOLANG\n"), 5)
fmt.Println(err)
}
环境变量相关
func osEnv() {
// 获取所有的环境变量
s := os.Environ()
fmt.Printf("evviron: %v\n", s)
// 获取某个环境变量
s2 := os.Getenv("GOPATH")
fmt.Printf("GOPATH: %v\n", s2)
// 设置环境变量
os.Setenv("env1", "env1")
s2 = os.Getenv("aaa")
fmt.Printf("aaa: %v\n", s2)
fmt.Println("-------------------")
// 查找
s3, b := os.LookupEnv("env1")
fmt.Printf("env1: %v\n", s3)
fmt.Printf("是否存在: %v\n", b)
// 清空环境变量
//os.Clearenv()
}
注意点
- os.Environ - 获取所有的环境变量
- os.Getenv - 获取某个环境变量
- os.Setenv - 设置某个环境变量
- os.LookupEnv - 查找某个环境变量,返回的是环境变量的值与是否存在
- os.Clearenv - 清空环境变量