postgresql 遍历参数_《go语言从入门到入坟》json操作、文件操作-程序员宅基地

技术标签: postgresql 遍历参数  

json操作

JSON (JavaScript Object Notation)是一种比XML更轻量级的数据交换格式,不仅易于阅读和理解,也更方面程序解析和生成。尽管json是JavaScript的一个子集,但是json采用完全独立于编程语言的文本模式,而且表现形式类似于键值对(如果你了解Python的话,那么你会发现json的字典很相似,其实json就是借鉴了Python中字典的结构),这使它成为了理想的、跨平台、跨语言的数据交换语言。

{

"name": "夏色祭",

"age": 16,

"gender": "female",

"中の人": {

"name": "佐藤希",

"age": 25,

"gender": "female"

}

}

开发者可以用 JSON 传输简单的字符串、数字、布尔值,也可以传输一个数组,或者一个更复杂 的复合结构。在 Web 开发领域中, JSON被广泛应用于 Web 服务端程序和客户端之间的数据通信。

Go语言内建对JSON的支持,我们可以使用内置的encoding/json包标准库,轻松地对json数据进行解析和生成。

下面就来看看吧。

结构体和json

生成json可以调用json.Marshal函数,或者json.MarshalIndent,两个函数是一样的,只不过后者会通过缩进使格式更美观一些。

func Marshal(v interface{}) ([]byte, error)

func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)

举个栗子:

package main

import (

"encoding/json"

"fmt"

)

type girl struct {

Name string

Age int

Hobby string

}

func main() {

g := girl{"夏色祭", 16, "まつり"}

res, err := json.Marshal(g)

if err != nil {

fmt.Println("err =", err)

}

fmt.Println(string(res))

//{"Name":"夏色祭","Age":16,"Hobby":"まつり"}

res, err = json.MarshalIndent(g, "", "\t")

if err != nil {

fmt.Println("err =", err)

}

fmt.Println(string(res))

/*

{

"Name": "夏色祭",

"Age": 16,

"Hobby": "まつり"

}

*/

}

但是有一点需要注意,结构的成员必须要大写,否则无法被导出成json。但如果我们就希望小写呢,答案是使用tag。

package main

import (

"encoding/json"

"fmt"

)

type girl struct {

Name string `json:"name"`

Age int `json:"age"`

Hobby string `json:"hobby"`

}

func main() {

g := girl{"夏色祭", 16, "まつり"}

res, err := json.Marshal(g)

if err != nil {

fmt.Println("err =", err)

}

fmt.Println(string(res))

//{"name":"夏色祭","age":16,"hobby":"まつり"}

}

除了根据结构体得到json,我们也可以将一个json解析成结构体。

package main

import (

"encoding/json"

"fmt"

)

type girl struct {

//使用`json:"xxx"`相当于起了一个别名xxx, 以后序列化出来的字段就叫这个名字

Name string `json:"name"`

Age int `json:"age"`

Hobby string `json:"hobby"`

}

func main() {

var g girl

s := `

{

"name": "神乐mea",

"age": 38,

"hobby": "money"

}

`

// 解析到结构体中的话, 可以使用json.Unmarshal

// 传入字符数组和结构体指针

err := json.Unmarshal([]byte(s), &g)

if err != nil {

fmt.Println("err =", err)

}

fmt.Println(g) // {神乐mea 38 money}

}

map和json

除了结构体和json可以互转之外, map也是可以的,当然调用的函数都是一样的,我们来看一下。

package main

import (

"encoding/json"

"fmt"

)

func main() {

// 创建一个保存键值对的映射

t1 := make(map[string]interface{})

t1["company"] = "博客园"

t1["subjects"] = []string{"Go", "Web", "Python", "C++"}

t1["isok"] = true

t1["price"] = 8980.88

res, err := json.MarshalIndent(t1, "", "\t")

if err != nil {

fmt.Println("err =", err)

}

fmt.Println(string(res))

/*

{

"company": "博客园",

"isok": true,

"price": 8980.88,

"subjects": [

"Go",

"Web",

"Python",

"C++"

]

}

*/

}

将json转成map也是可以的,使用的也是同一个函数:

package main

import (

"encoding/json"

"fmt"

)

func main() {

s := `

{

"company": "博客园",

"isok": true,

"price": 8980.88,

"subjects": [

"Go",

"Web",

"Python",

"C++"

]

}

`

//默认返回值类型为interface类型, 我们以map类型进行格式存储

//可以理解为: json的key为map的key, json的value为map的value

//格式: map[string]interface{}

var t interface{}

err := json.Unmarshal([]byte(s), &t)

if err != nil {

fmt.Println("err =", err)

}

//因为map是无序的, 所以打印的结果不一定和我们想象的一样

fmt.Println(t) // map[company:博客园 isok:true price:8980.88 subjects:[Go Web Python C++]]

// 使用断言判断类型

m := t.(map[string]interface{})

for k, v := range m {

switch val := v.(type) {

case string:

fmt.Println(k, "is string", val)

case int:

fmt.Println(k, "is int", val)

case float64:

fmt.Println(k, "is float64", val)

case bool:

fmt.Println(k, "is bool", val)

case []interface{}:

fmt.Println(k, "is array")

for i, u := range val {

fmt.Println(i, u)

}

default:

fmt.Println("Unknown type")

}

}

/*

company is string 博客园

isok is bool true

price is float64 8980.88

subjects is array

0 Go

1 Web

2 Python

3 C++

*/

}

将数据结构转成json这一步称之为序列化,根据json得到相应数据结构这一步称之为反序列化。

而除了json之外,在Go中还有两种序列化和反序列化的方式,我们来看一下。

gob

标准库gob是Go语言提供的 "私有" 的编解码方式,它的效率会比json,xml等更高,特别适合在Go语言程序间传递数据。

它的序列化和反序列化同样很简单:

package main

import (

"bytes"

"encoding/gob"

"fmt"

)

type Girl struct {

Name string

Age int `json:"age"`

Gender string `json:"gender"`

Where string `json:"where"`

Is_married bool `json:"is_married"`

}

func main() {

g := Girl{"satori", 16, "f", "东方地灵殿", false}

//创建缓存

buf := new(bytes.Buffer)

//把指针丢进去

enc := gob.NewEncoder(buf)

//调用Encode进行序列化

if err := enc.Encode(g); err != nil {

fmt.Println(err)

return

} else {

//序列化的内容会被放进buf里面

fmt.Println(buf.String())

/*

G��Girl�� Name Age Gender Where

Is_married !��satori f东方地灵殿

*/

}

}

发现是乱码,因为这类似Python的pickle,是该语言独有的。所以我们不认识没关系,Go编译器认识就行了

package main

import (

"bytes"

"encoding/gob"

"fmt"

)

type Girl struct {

Name string

Age int `json:"age"`

Gender string `json:"gender"`

Where string `json:"where"`

Is_married bool `json:"is_married"`

}

func main() {

g := Girl{"satori", 16, "f", "东方地灵殿", false}

buf := new(bytes.Buffer)

enc := gob.NewEncoder(buf)

if err := enc.Encode(g);err != nil {

fmt.Println(err)

return

}

var g1 = Girl{}

//bytes.NewBuffer和bytes.Buffer类似,只不过可以传入一个初始的byte数组,返回一个指针

dec := gob.NewDecoder(bytes.NewBuffer(buf.Bytes()))

//调用Decode方法,传入结构体对象指针,会自动将buf.Bytes()里面的内容转换成结构体

if err := dec.Decode(&g1);err != nil {

fmt.Println(err)

return

} else {

fmt.Println(g1) // {satori 16 f 东方地灵殿 false}

}

}

msgpack

MessagePack是一种高效的二进制序列化格式。它允许你在多种语言(如JSON)之间交换数据。但它更快更小。

这个包属于第三方,我们使用的话需要先安装:go get -u github.com/vmihailenco/msgpack,而且这个包的接口和标准库json是一致的。

package main

import (

"fmt"

"github.com/vmihailenco/msgpack"

)

type Girl struct {

Name string

Age int `json:"age"`

Gender string `json:"gender"`

Where string `json:"where"`

Is_married bool `json:"is_married"`

}

func main() {

g := Girl{"satori", 16, "f", "东方地灵殿", false}

//这个没有MarshalIndent

if ret, err := msgpack.Marshal(g); err != nil {

fmt.Println(err)

return

} else {

fmt.Println(string(ret)) //��Name�satori�Age� �Gender�f�Where�东方地灵殿�Is_married�

var g1 = Girl{}

if err := msgpack.Unmarshal(ret, &g1); err != nil {

fmt.Println(err)

return

} else {

fmt.Println(g1) // {satori 16 f 东方地灵殿 false}

}

}

}

文件操作

下面说一下Go语言中的文件操作,操作文件想必再熟悉不过了,Go语言中处理文件有一个特点,就是不用指定编码,因为默认是utf-8编码。

那么我们来看看在Go里面如何操作文件吧。

创建文件并写入内容、打开文件并读取内容

首先是创建文件并写入内容:

首先是创建文件,创建文件使用os.Create函数:

package main

import (

"fmt"

"os"

)

func main() {

// 根据提供的文件名创建一个新的文件, 返回一个文件句柄 和 一个错误信息

// 如果创建失败, 那么file为nil, err为错误信息; 创建成功file为对应的文件句柄, err为nil

file, err := os.Create("1.txt")

if err != nil {

panic(fmt.Sprintf("文件创建失败, 失败原因: %s\n", err.Error()))

}

// 写入内容, 可以调用WriteString写入字符串, 也可以调用write写入字节数组

_, _ = file.Write([]byte("古明地觉"))

_, _ = file.WriteString("你好呀")

// 这两个方法都会返回一个 int 和 一个error, 分别表示写入的字节数和错误信息

// 写入成功: 返回 写入字节数 和 nil; 写入失败: 返回 0 和 错误信息

// 最后记得关闭文件, 当然最好的办法是在创建文件之后, 就是用defer语句

file.Close()

}

该文件写入时的权限默认是0666,并且使用os.Create时如果文件已经存在,那么会先将文件清空。

然后是读取文件,读取文件使用的是os.Open函数:

package main

import (

"fmt"

"os"

)

func main() {

// 指定文件名, 默认以utf-8编码模式打开文件, 同样会返回一个文件句柄和错误信息

// 如果文件不存在: 那么就会报错, error不为nil

file, err := os.Open("1.txt")

if err != nil {

panic(fmt.Sprintf("文件打开失败, 错误信息:%s\n", err.Error()))

}

defer file.Close()

// 下面来读取文件, 读取文件使用Read方法即可

// 我们需要指定一个切片, 会将内容都读到切片中, 一般指定长度为1024

buf := make([]byte, 1024)

//此时文件的内容都会读到buf里面, n则是写入了多少个字节, n不会超过切片buf的长度

n, err := file.Read(buf)

// 将写入的内容读取出来

fmt.Println(string(buf[: n])) // 你好呀古明地觉

}

我们注意到:当前指定的buf的长度为1024,那如果文件的字节数超过1024该怎么办呢?于是我们可以将长度变得更大一些,但是到底要弄多大呢?这是一个未知数。弄小了一次读不完,要是弄大了,会浪费。因此最好的办法,不要一次就读完,而是循环读取,这样不就好了吗?

这里我手动往1.txt文件里面写入一些内容吧。

package main

import (

"fmt"

"io"

"os"

)

func main() {

// 指定文件名, 默认以utf-8编码模式打开文件, 同样会返回一个文件句柄和错误信息

// 如果文件不存在: 那么就会报错, error不为nil

file, err := os.Open("1.txt")

if err != nil {

panic(fmt.Sprintf("文件打开失败, 错误信息:%s\n", err.Error()))

}

defer file.Close()

buf := make([]byte, 12) // 存放文件内容的缓存,相当于中转站

data := make([]byte, 0, 1024) // 用来存放文件内容,buf读取的内容都会写到data里面去

for {

//无限循环,不断读取

n, err := file.Read(buf)

// 什么时候文件读完呢?如果文件读完的话,那么err不为nil,而是io.EOF

// 所以我们可以进行判断

if err != nil {

//如果err != nil说明出错了,但如果还等于io.EOF的话,说明读完了,因为文件读完,err也不为nil。直接break

if err == io.EOF {

break

} else {

//如果错误不是io.EOF的话,说明就真的在读取中出现了错误,直接panic出来

panic(err)

}

}

//此时文件内容写到buf里面去了,写了多少个呢?写了n个,那么我们再写到data里面去

data = append(data, buf[:n]...)

//我们来打印一下,每次写了多少个字节

fmt.Printf("往data中写入%d个字节\n", n)

/*

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入12个字节

往data中写入6个字节

*/

}

//写完之后,我们来打印一下

fmt.Println(string(data))

/*

白色相簿什么的,已经无所谓了。

因为已经不再有歌,值得去唱了。

传达不了的恋情,已经不需要了。

因为已经不再有人,值得去爱了。

*/

}

以上便是文件的基本操作,注意:在读取的时候我们指定了buf和data两个切片,buf切片用于接收文件的内容,接收完毕之后再写入到data里面去。并且为了演示,我们的buf的长度指定为12,比较少,一般指定为1024。

无论写入还是读出,我们从前往后,但是我们还可以在指定位置写入、在指定位置读取,举个栗子:

package main

import (

"fmt"

"os"

)

func main() {

file, err := os.Create("1.txt")

if err != nil {

panic(fmt.Sprintf("文件创建失败, 失败原因: %s\n", err.Error()))

}

_, _ = file.Write([]byte("古明地觉"))

_, _ = file.WriteString("你好呀")

// 我们可以调用ReadAt在指定位置写入, 在偏移量为9的位置写入 "恋"

// 依旧返回一个 int 和 error, 表示写入的字节数 以及 错误信息

_, _ = file.ReadAt([]byte("恋"), 9)

}

然后我们读取一下看看:

package main

import (

"fmt"

"io"

"os"

)

func main() {

file, err := os.Open("1.txt")

if err != nil {

panic(fmt.Sprintf("文件打开失败, 错误信息:%s\n", err.Error()))

}

defer file.Close()

buf := make([]byte, 1024)

data := make([]byte, 0, 1024)

for {

n, err := file.Read(buf)

if err != nil {

if err == io.EOF {

break

} else {

panic(err)

}

}

data = append(data, buf[:n]...)

}

fmt.Println(string(data)) // 古明地恋你好呀

}

我们在读取之后发现"觉"被替换成了"恋","古明地"总共是9字节,因此在偏移量为9的位置写入正好把"觉"这个字符给替换掉了。从这里我们也能看出,这里在中间位置写入的时候会将后面的内容覆盖掉。当然读取的话也有一个ReadAt,可以自己试一下。但无论是WriteAt还是ReadAt我们用的都比较少,更推荐的方式是移动光标,后面会说。

os.OpenFile

其实无论是os.Create还是os.Open,它们底层都调用了os.OpenFile函数,我们来看一下。

package main

import (

"fmt"

"os"

)

func main() {

// OpenFile接收三个参数

// 1.文件名

// 2.文件的模式, 支持如下

/*

os.O_RDONLY: 以只读的方式打开

os.O_WRONLY: 以只写的方式打开

os.O_RDWR: 以读写的方式打开

os.O_NONBLOCK: 打开时不阻塞

os.O_APPEND: 以追加的方式打开

os.O_CREAT: 创建并打开一个新文件

os.O_TRUNC: 打开一个文件并截断它的长度为零(必须有写权限)

os.O_EXCL: 如果指定的文件存在,返回错误

os.O_SHLOCK: 自动获取共享锁

os.O_EXLOCK: 自动获取独立锁

os.O_DIRECT: 消除或减少缓存效果

os.O_FSYNC : 同步写入

os.O_NOFOLLOW: 不追踪软链接

*/

// 3.权限,一般设置为0666,这在linux下有用,Windows下面没太大卵用

// 以只写的方式打开,并且写入的时候,是以追加的形式写入

file, _ := os.OpenFile(`1.txt`, os.O_WRONLY|os.O_APPEND, 0666)

_, _ = file.Write([]byte("\n这是新的内容,但是原来的内容还在"))

// 关闭文件

defer file.Close()

//写入之后,我们再以只读方式打开

file, _ = os.OpenFile(`1.txt`, os.O_RDONLY, 0666)

buf := make([]byte, 1024)

n, _ := file.Read(buf)

fmt.Println(string(buf[:n]))

/*

古明地恋你好呀

这是新的内容,但是原来的内容还在

*/

}

下面说一说光标,首先我们上面写入内容之后关闭文件,然后再打开文件是不是比较麻烦呢,可不可以用读写模式打开呢?

package main

import (

"fmt"

"os"

)

func main() {

// OpenFile接收三个参数

file, err := os.OpenFile(`1.txt`, os.O_RDWR|os.O_TRUNC, 0666)

if err != nil {

panic(err)

}

_, _ = file.Write([]byte("你好呀, 古明地觉"))

buf := make([]byte, 1024)

n, _ := file.Read(buf)

fmt.Printf("%q\n", string(buf[: n])) // ""

}

我们发现明明写入了内容,但是却什么也没有读到,这里便涉及到文件的光标了。光标就是当前所处的位置,默认在读取的时候只能往后读;而上面在写完内容之后,光标就直接停在结尾处了,所以此时当然什么也读不到啦。所以解决办法就是将光标进行移动即可,而移动光标可以通过file.Seek函数:

func (f *File) Seek(offset int64, whence int) (ret int64, err error)

/*

offset表示向后移动多少个字节

whence表示位置: 0表示文件的开头、1表示当前光标的所在位置、2表示文件的结尾

*/

// 返回光标移动后所处的位置, 以及错误信息

f.Seek(0, 0): 从文件的开始位置向后移动0字节, 相当于将光标调整到文件开始位置;

f.Seek(9, 0): 将光标移动到文件偏移量为9的位置;

f.Seek(3, 1): 将光标从当前位置向后移动3字节

f.Seek(-3, 2): 将光标从文件结尾位置向前移动3字节

下面来演示一下:

package main

import (

"fmt"

"os"

)

func main() {

file, err := os.OpenFile(`1.txt`, os.O_RDWR|os.O_TRUNC, 0666)

if err != nil {

panic(err)

}

_, _ = file.Write([]byte("你好呀古明地觉"))

// 我们从结尾处向前移动3字节, 所以移动后光标所处的位置就是 6 * 3 = 18 的位置

pos, _ := file.Seek(-3, 2)

fmt.Println(pos) // 18

buf := make([]byte, 1024)

n, _ := file.Read(buf)

fmt.Printf("%q\n", string(buf[: n])) // "觉"

// 移动到开始的位置

_, _ = file.Seek(0, 0)

n, _ = file.Read(buf)

fmt.Printf("%q\n", string(buf[: n])) // "你好呀古明地觉"

}

以上便是光标,对啦,如果想知道光标某一个时刻的所处位置该怎么办呢?很简单,f.Seek(0, 1),从当前位置向后移动0个字节不就是当前所处的位置了吗?

然后再来说说os.OpenFile的第二个参数,也就是模式:

1. 在文件不存在的时候, 必须指定os.O_CREATE; 如果文件存在的话可以不用指定;

2. os.O_TRUNC表示打开的时候清空文件, os.O_APPEND表示打开文件的时候不清空并自动在结尾处追加, 所以这两个参数不可以同时指定;

3. 指定os.O_CREATE会在文件不存在时创建; 如果文件存在并且在不指定os.O_APPEND的时候, 光标会自动处于文件的开始位置; 如果读取的话可以将内容全部读取出来, 写入的话会从开始位置写入、因此会将后面的内容覆盖掉;如果指定了os.O_APPEND, 那么光标会处于文件的结尾, 写入的时候会向后追加, 但是读取的时候只会得到空字符串, 因为后面没有内容了, 想要读取内容的话需要手动移动光标;

4. os.O_RDONLY表示只读;O_WRONLY表示只写;os.O_RDWR表示可读可写, 但如果文件不存在则它们都需要搭配os.O_CREATE使用;

5. 打开的文件默认是可读可写的, 一般不需要指定os.O_RDWR; 所以写入文件的话, 指定O_CREATE|O_APPEND或者O_CREATE|O_TRUNC即可, 表示追加写入或者清空写入; 读取文件直接指定O_CREATE, 当然这种情况也是可写的, 但是我们一般不这么做; 同时读写文件的话, 指定O_CREATE|O_APPEND即可, 因为一开始文件可能有内容所以不使用O_TRUNC; 当然啦, 通过光标我们可以更加灵活的进行控制

6. 如果就希望只读或者只写的话, 可以使用O_RDONLY或者O_WRONLY

文件属性

文件是具有很多属性的,比如:大小、创建时间、类型等等,那么这些属性在Go中如何查看呢?

package main

import (

"fmt"

"os"

)

func main() {

//打开文件使用os.Open函数,会返回一个文件句柄和一个error

file, err := os.Open(`1.txt`)

if err != nil {

fmt.Println("文件打开失败:",err)

}

//调用file.Stat()可以查看文件的信息,这是一个os.FileInfo对象

info, err := file.Stat()

if err != nil {

panic(err)

}

//属性如下

/*

type FileInfo interface {

Name() string // 文件名

Size() int64 // 文件的大小,按字节计算

Mode() FileMode // 文件的模式

ModTime() time.Time // 修改时间

IsDir() bool // 是否是目录

Sys() interface{} // 数据源,一般不用管

}

*/

fmt.Println(info.Name()) // 1.txt

fmt.Println(info.Size()) // 21

//有点类似于linux里面的,第一个-表示文本文件,后面的三个rw-表示可读可写不可执行。

//分别是用户、用户所属组、其他组的权限

fmt.Println(info.Mode()) // -rw-rw-rw-

fmt.Println(info.ModTime()) // 2019-12-18 19:52:44.3146692 +0800 CST

fmt.Println(info.IsDir()) // false

fmt.Println(info.Sys()) // &{32 {1621963324 30848071} {664622106 30848084} {664622106 30848084} 0 21}

}

使用bufio库来读取文件

bufio相当于是在os.OpenFile得到的文件句柄之上进行一层封装,bufio,从名字上也能看出来是带缓存的io。

package main

import (

"bufio"

"fmt"

"io"

"os"

)

func main() {

file, _ := os.Open(`1.txt`)

//使用bufio.NewReader进行一层包装

reader := bufio.NewReader(file)

//首先这个reader,可以像file一样,使用Read方法

//然而reader还可是按照指定字符来读,比如我想一行一行读,就可以指定换行符来读

for {

//返回string和error

s, err := reader.ReadString('\n') //表示每读到\n就停止

//这里使用print,因为文件本身有换行符,println自带换行,所以使用print

fmt.Print("读取一行:", s)

/*

读取一行:白色相簿什么的,已经无所谓了。

读取一行:因为已经不再有歌,值得去唱了。

读取一行:传达不了的恋情,已经不需要了。

读取一行:因为已经不再有人,值得去爱了。

*/

if err != nil {

if err == io.EOF {

break

} else {

panic(err)

}

}

}

}

除了NewReader,还有一个NewScanner:

package main

import (

"bufio"

"bytes"

"fmt"

"os"

)

func main() {

file, _ := os.Open(`1.txt`)

scanner := bufio.NewScanner(file)

for scanner.Scan(){

//可以看到我们使用println打印,行与行之间没有空隙,说明scanner.Text()没有把换行符读进去。

fmt.Println(scanner.Text())

/*

白色相簿什么的,已经无所谓了。

因为已经不再有歌,值得去唱了。

传达不了的恋情,已经不需要了。

因为已经不再有人,值得去爱了。

*/

}

//但是这都是一行一行读的,我们可以写到缓存里面去

//这个缓存使用bytes.Buffer{}来创建

buf := bytes.Buffer{}

file, _ = os.Open(`1.txt`)

scanner = bufio.NewScanner(file)

for scanner.Scan(){

//直接调用buf.WriteString即可, 当然还可以使用buf.Write写入字节

buf.WriteString(scanner.Text())

//scanner.Text()得到字符串, 也可以使用scanner.Bytes()得到字节

}

//当调用buf.String()拿到String

//也可以调用buf.Bytes()拿到字节

fmt.Println(buf.String()) // 白色相簿什么的,已经无所谓了。因为已经不再有歌,值得去唱了。传达不了的恋情,已经不需要了。因为已经不再有人,值得去爱了。

//因为没有读取换行符,所以是连在一起的

//这里再提一下bytes.Buffer{},这是一个非常方便的字节缓存。用来组合字符串非常方便

buffer := bytes.Buffer{}

buffer.WriteString("哈哈")

buffer.WriteString("呱呱")

buffer.Write([]byte("嘻嘻"))

fmt.Println(buffer.String()) // 哈哈呱呱嘻嘻

fmt.Println(buffer.Bytes()) // [229 147 136 229 147 136 229 145 177 229 145 177 229 152 187 229 152 187]

//当然buffer也有ReadString,和Read方法

s, _ := buffer.ReadString('\n')

fmt.Println(s) // 哈哈呱呱嘻嘻

buffer.WriteString("你胸大,你先说")

b := make([]byte, 1024)

n, _ := buffer.Read(b)

fmt.Println(string(b[: n])) // 你胸大,你先说

}

使用ioutil模块

使用ioutil读取文件更加的方便,我们来看一下:

package main

import (

"fmt"

"io/ioutil"

"os"

)

func main() {

file, _ := os.Open(`1.txt`)

// 直接将file丢进去,可以读取全部内容

s, _ := ioutil.ReadAll(file)

fmt.Println(string(s))

/*

白色相簿什么的,已经无所谓了。

因为已经不再有歌,值得去唱了。

传达不了的恋情,已经不需要了。

因为已经不再有人,值得去爱了。

*/

// 是不是很方便呢?其实还有更方便的

//调用ReadFile,传入文件名直接得到字节数组和error。当然底层是使用了os.Open和ioutil.ReadAll

s, _ = ioutil.ReadFile(`1.txt`)

fmt.Println(string(s))

/*

白色相簿什么的,已经无所谓了。

因为已经不再有歌,值得去唱了。

传达不了的恋情,已经不需要了。

因为已经不再有人,值得去爱了。

*/

}

当然ioutil开可以写入文件:

package main

import (

"bytes"

"fmt"

"io/ioutil"

)

func main() {

buf := bytes.Buffer{}

buf.WriteString("明明是我先来的\n")

buf.WriteString("为什么会变成这样呢\n")

buf.WriteString("何でそんなに慣れてんだよ\n")

buf.WriteString("雪菜と何度もキースしたんだよ")

//传入filename,content,权限

_ = ioutil.WriteFile(`1.txt`, buf.Bytes(), 0666)

//读取出来看看

s, _ := ioutil.ReadFile(`1.txt`)

fmt.Println(string(s))

/*

明明是我先来的

为什么会变成这样呢

何でそんなに慣れてんだよ

雪菜と何度もキースしたんだよ

*/

}

之前说ioutil很强大,是因为还有别的用处,比如读取目录:

package main

import (

"fmt"

"io/ioutil"

)

func main() {

files, _ := ioutil.ReadDir(`C:\go`)

//返回一个[]os.FileInfo和error

for _, file := range files {

if file.IsDir() {

fmt.Println(file.Name(), "是目录")

} else {

fmt.Println(file.Name(), "是文件")

}

/*

AUTHORS 是文件

CONTRIBUTING.md 是文件

CONTRIBUTORS 是文件

LICENSE 是文件

PATENTS 是文件

README.md 是文件

SECURITY.md 是文件

VERSION 是文件

api 是目录

bin 是目录

doc 是目录

favicon.ico 是文件

lib 是目录

misc 是目录

pkg 是目录

robots.txt 是文件

src 是目录

test 是目录

*/

}

}

读取命令行

下面来看看如何从命令行中读取参数:

package main

import (

"fmt"

"os"

)

func main() {

// 会返回一个[]string

args := os.Args

// 命令行输入: go run 1.go 夏色祭 16 "夏哥 祭妹"

for _, v := range args[1:]{

// 第一个参数是可执行文件名, 我们不用管

fmt.Println(v)

/*

夏色祭

16

夏哥 祭妹

*/

}

}

这种方式非常简单,但是功能也不强,因为它默认所有参数都是字符串。于是我们可以使用一个标准库,叫做flag,来看看用法。

package main

import (

"flag"

"fmt"

)

func main() {

//flag.Type里面接受三个参数,指定的名字,默认值,描述信息

Name := flag.String("name", "mashiro", "姓名")

Age := flag.Int("age", 16, "年龄")

Has_bf := flag.Bool("has_bf", false, "有男朋友?")

//解析

flag.Parse()

/*

我们在命令行中便可以通过name satori age 16 has_bf false这种方式指定

当然还可以使用其他方式比如 --name satori、 -name satori、 --name=satori、 -name=satori

*/

//但是注意:得到的Name、Age、Has_bf都是指针

fmt.Println(*Name, *Age, *Has_bf)

}

flag的其他参数

package main

import (

"flag"

"fmt"

)

func main() {

Name := flag.String("name", "mashiro", "姓名")

Age := flag.Int("age", 16, "年龄")

Has_bf := flag.Bool("has_bf", false, "有男朋友?")

flag.Parse()

fmt.Println(*Name, *Age, *Has_bf)

//命令行后的其他参数,是一个[]string类型

fmt.Println(flag.Args())

//命令行后的其他参数个数

fmt.Println(flag.NArg())

//命令行使用的参数个数

fmt.Println(flag.NFlag())

}

我们后面多指定了a b c 1,所以可以通过flag.Args来获取,flag.NArgs就是多指定的参数个数,flag.NFlag则是我们在命令行,通过指定关键字的方式指定的参数个数,这里是2,因为has_bf我们没有指定,但即便如此也是打印了默认值的。

flag模块还可以使用一种方式,flag.TypeVar,这和flag.Type是基本类似的。

package main

import (

"flag"

"fmt"

)

func main() {

var Name string

var Age int

var Has_bf bool

flag.StringVar(&Name, "name", "mashiro", "姓名")

flag.IntVar(&Age, "age", 16, "年龄")

flag.BoolVar(&Has_bf, "has_bf", false, "有男朋友?")

flag.Parse()

fmt.Println(Name, Age, Has_bf)

fmt.Println(flag.Args())

fmt.Println(flag.NArg())

fmt.Println(flag.NFlag())

}

flag.Type是直接返回一个指针,flag.TypeVar则是需要先声明变量,然后把指针传进去,至于后面的参数、以及结果都是一样的。

文件路径处理

这里推荐一个标准库叫filepath,它在处理文件路径的时候非常方便。

1. ToSlash(path string) string:将相关平台的路径分隔符转为/

package main

import (

"fmt"

"os"

"path/filepath"

)

func main() {

sep := os.PathSeparator

// 查看当前平台的系统路径分隔符,windows平台是\

fmt.Println(string(sep)) // \

// 将分割符转为/

fmt.Println(filepath.ToSlash(`C:\go\bin\go.exe`)) // C:/go/bin/go.exe

// 注意:该函数不在意路径是否存在,只是当成普通的字符串进行处理

// 比如我输入一个不存在的路径也是可以的

fmt.Println(filepath.ToSlash(`C:\go\go\go\bin\go.exe`)) // C:/go/go/go/bin/go.exe

}

2. FromSlash(path string) string:和ToSlash相反,是将/转化为相关系统的路径分隔符

package main

import (

"fmt"

"path/filepath"

)

func main() {

fmt.Println(filepath.FromSlash(`C:/python37/python.exe`)) // C:\python37\python.exe

fmt.Println(filepath.FromSlash(`C:\python37/python.exe`)) // C:\python37\python.exe

fmt.Println(filepath.FromSlash(`C:\python37\python.exe`)) // C:\python37\python.exe\\\\

/*

可以看到,这两个函数只是简单的字符串替换罢了,在源码里面也是这么做的

func FromSlash(path string) string {

if Separator == '/' {

return path

}

return strings.ReplaceAll(path, "/", string(Separator))

}

另外,这两个函数在linux下面也能用,但是没有意义,因为linux的路径分隔符就是/

*/

}

3. Dir(path string) string:获取path中最后一个分割符前面的部分,类似于Python中的os.path.dirname(path)

package main

import (

"fmt"

"path/filepath"

)

func main() {

path := `c:\python37\python.exe`

fmt.Println(filepath.Dir(path)) // c:\python37

}

4. Base(path string) string:获取path中最后一个分割符后面的部分,类似于Python中的os.path.basename(path)

package main

import (

"fmt"

"path/filepath"

)

func main() {

path := `c:\python37\python.exe`

fmt.Println(filepath.Base(path)) // python.exe

}

5. Split(path string) (dir, file string):相当于是Dir和Base的组合,得到最后一个分割符的前面和后面两部分,类似于Python中os.path.split

package main

import (

"fmt"

"path/filepath"

)

func main() {

path := `c:\python37\python.exe`

dir, file := filepath.Split(path)

fmt.Println(dir, file) // c:\python37\ python.exe

}

6. Ext(path string) string:获取path中的文件扩展名,类似于Python中的os.path.splitext(path)[1]

package main

import (

"fmt"

"path/filepath"

)

func main() {

path := `c:\python37\python.exe`

fmt.Println(filepath.Ext(path)) // .exe

}

7. Rel(basepath, targpath string) (string, error):获取targpath相对于basepath的路径,怎么理解呢?就是basepath进行什么样的操作,才能得到targpath。其中两者必须都是相对路径或者绝对路径

package main

import (

"fmt"

"path/filepath"

)

func main() {

path1 := `c:\python37\python.exe`

path2 := `c:\python37`

p1, err1 := filepath.Rel(path1, path2)

if err1 != nil {

fmt.Println(err1)

} else {

fmt.Println(p1) // ..

}

//得到的结果是..,表示path1组合..就能得到path2

path1 = `c:\python37`

path2 = `c:\python37\python.exe`

p2, err2 := filepath.Rel(path1, path2)

if err2 != nil {

fmt.Println(err2)

} else {

fmt.Println(p2) // python.exe

}

// 表示path1再组合python.exe就能得到path2

path1 = `c:\python37`

path2 = `c:\go`

p3, err3 := filepath.Rel(path1, path2)

if err3 != nil {

fmt.Println(err3)

} else {

fmt.Println(p3) // ..\go

}

path1 = `c:\python37`

path2 = `d:\overwatch`

p4, err4 := filepath.Rel(path1, path2)

if err4 != nil {

fmt.Println(err4) // Rel: can't make d:\overwatch relative to c:\python37

} else {

fmt.Println(p4)

}

//在window上,如果跨越了盘符,是没有办法的

}

8. Join(elem ...string) string:将多个路径进行组合

package main

import (

"fmt"

"path/filepath"

)

func main() {

path1 := `c:\python37`

path2 := `lib`

path3 := `site-packages`

path4 := `tornado`

fmt.Println(filepath.Join(path1, path2, path3, path4)) // c:\python37\lib\site-packages\tornado

fmt.Println(filepath.Join(path1, path2, "scripts", "pip")) // c:\python37\lib\scripts\pip

fmt.Println(filepath.Join(path1, path2, "..", "scripts", "pip")) // c:\python37\scripts\pip

// ..相当于上一层目录

}

9. Clean(path string) string:清理路径中的多余字符

package main

import (

"fmt"

"path/filepath"

)

func main() {

path := `c:\python\\\python37\..\\\python.ext\\\aaa\.\::::\\xx`

fmt.Println(filepath.Clean(path)) // c:\python\python.ext\aaa\::::\xx

// 清除的主要是\\\和\\, 都换成了\,个人觉得不是很常用

}

10. Abs(path string) (string, error):获取path的绝对路径,类似于python中的os.path.abspath

package main

import (

"fmt"

"path/filepath"

)

func main() {

path1 := `.`

abs_path1, err1 := filepath.Abs(path1)

if err1 != nil {

fmt.Println(err1)

} else {

fmt.Println(abs_path1) // D:\go

}

//如果是点的话,那么默认是当前go文件所在的工作区的目录

}

11. IsAbs(path string) bool:判断当前路径是否是绝对路径

package main

import (

"fmt"

"path/filepath"

)

func main() {

path1 := `.`

flag := filepath.IsAbs(path1)

fmt.Println(flag) // false

fmt.Println(filepath.IsAbs(`c:\python37\python.exe`)) // true

}

12. VolumeName(path string) string:返回path所在的卷名,比如c:\python37\python.exe就是c:,而linux中/opt/python/bin就是/opt/python

package main

import (

"fmt"

"path/filepath"

)

func main() {

path1 := `c:\python37\python.exe`

fmt.Println(filepath.VolumeName(path1)) // c:

}

13. EvalSymlinks(path string) (string, error):返回当前链接(快捷方式)所指向的文件

14. Match(pattern, name string) (matched bool, err error),判断 name 是否和指定的模式 pattern 完全匹配,有点类似于Python中的fnmatch,但是匹配的方式不太一样

package main

import (

"fmt"

"path/filepath"

)

func main() {

/*

?:匹配单个任意字符

*:匹配任意个任意字符

[]:匹配某个范围内的任意一个字符

[^]:匹配某个范围外的任意一个字符

[a-z]:也可以使用类似于正则表达式的模式,使用-表示一个区间

\:用来进行转义,匹配实际的字符,比如\*表示*, \[匹配[, 但是?是不需要转义的,因为?表示匹配任意一个字符,所以也包含?

[]里面也可以直接包含[ ? *等特殊字符,无需转义。但是] -这些字符则必须要转义,必须是\]或者\-才能匹配]和-

*/

fmt.Println(filepath.Match(`???`, "abc")) // true

fmt.Println(filepath.Match(`???`, "???")) // true

fmt.Println(filepath.Match(`???`, "abcd")) // false

fmt.Println(filepath.Match(`*`, "abc")) // true

fmt.Println(filepath.Match(`*`, "")) // true

fmt.Println(filepath.Match(`???[?`, "abc[e")) // false syntax error in pattern

fmt.Println(filepath.Match(`[aA][bB][cC]`, `aBc`)) // true

fmt.Println(filepath.Match(`[^aA]*`, `abc`)) // false

fmt.Println(filepath.Match(`[a-z]*`, `a+b`)) // true

}

15. Glob(pattern string) (matches []string, err error),列出与指定的模式 pattern 完全匹配的文件或目录(匹配原则同Match)

package main

import (

"fmt"

"io/ioutil"

"path/filepath"

)

func main() {

list, err := filepath.Glob(`c:\python37\*`)

if err != nil {

fmt.Println(err)

} else {

for _, v := range list {

fmt.Println(v)

/*

c:\python37\DLLs

c:\python37\Doc

c:\python37\LICENSE.txt

c:\python37\Lib

c:\python37\NEWS.txt

c:\python37\Scripts

c:\python37\Tools

c:\python37\cx_Oracle-doc

c:\python37\etc

c:\python37\include

c:\python37\libs

c:\python37\man

c:\python37\python.exe

c:\python37\python3.dll

c:\python37\python37.dll

c:\python37\pythonw.exe

c:\python37\share

c:\python37\tcl

c:\python37\vcruntime140.dll

*/

}

}

//遍历文件还有另一种方式

fileinfo, err := ioutil.ReadDir(`c:\python37`)

if err != nil {

fmt.Println(err)

} else {

// fileinfo则是一个切片,里面的数据类型是os.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() interface{} // underlying data source (can return nil)

}

*/

for _, v := range fileinfo {

message := fmt.Sprintf("文件名:%s,大小:%d,是否是目录,%t", v.Name(), v.Size(), v.IsDir())

fmt.Println(message)

/*

文件名:DLLs,大小:0,是否是目录,true

文件名:Doc,大小:0,是否是目录,true

文件名:LICENSE.txt,大小:30195,是否是目录,false

文件名:Lib,大小:0,是否是目录,true

文件名:NEWS.txt,大小:665470,是否是目录,false

文件名:Scripts,大小:0,是否是目录,true

文件名:Tools,大小:0,是否是目录,true

文件名:cx_Oracle-doc,大小:0,是否是目录,true

文件名:etc,大小:0,是否是目录,true

文件名:include,大小:0,是否是目录,true

文件名:libs,大小:0,是否是目录,true

文件名:man,大小:0,是否是目录,true

文件名:python.exe,大小:99856,是否是目录,false

文件名:python3.dll,大小:58896,是否是目录,false

文件名:python37.dll,大小:3748368,是否是目录,false

文件名:pythonw.exe,大小:98320,是否是目录,false

文件名:share,大小:0,是否是目录,true

文件名:tcl,大小:0,是否是目录,true

文件名:vcruntime140.dll,大小:89752,是否是目录,false

*/

}

}

}

16. Walk(root string, walkFn WalkFunc) error:遍历指定目录下的所有子目录,对遍历的项目使用walkFn进行处理,WalkFunc类型如下。

type WalkFunc func(path string, info os.FileInfo, err error) error

package main

import (

"fmt"

"os"

"path/filepath"

"strings"

)

func main() {

walkFn := func(path string, info os.FileInfo, err error) error {

//遍历的时候,会自动将path:文件路径、info:文件信息、err:错误传递进来,我们可以写上自己的逻辑

//获取文件名

filename := info.Name()

if strings.HasSuffix(filename, "__init__.py") {

//如果文件是以__init__.py结尾的话, 直接打印对应的path

fmt.Println(path)

}

//这里我们直接返回nil即可

return nil

}

//那么开始遍历,会对遍历的每一个内容都交给walkFn进行处理

err := filepath.Walk(`c:\python37\lib\site-packages\numpy`, walkFn)

if err != nil {

fmt.Println("err =", err)

}

/*

输出结果

c:\python37\lib\site-packages\numpy\__init__.py

c:\python37\lib\site-packages\numpy\compat\__init__.py

c:\python37\lib\site-packages\numpy\compat\tests\__init__.py

c:\python37\lib\site-packages\numpy\core\__init__.py

c:\python37\lib\site-packages\numpy\core\tests\__init__.py

c:\python37\lib\site-packages\numpy\distutils\__init__.py

c:\python37\lib\site-packages\numpy\distutils\command\__init__.py

c:\python37\lib\site-packages\numpy\distutils\fcompiler\__init__.py

c:\python37\lib\site-packages\numpy\distutils\tests\__init__.py

c:\python37\lib\site-packages\numpy\doc\__init__.py

c:\python37\lib\site-packages\numpy\f2py\__init__.py

c:\python37\lib\site-packages\numpy\f2py\tests\__init__.py

c:\python37\lib\site-packages\numpy\fft\__init__.py

c:\python37\lib\site-packages\numpy\fft\tests\__init__.py

c:\python37\lib\site-packages\numpy\lib\__init__.py

c:\python37\lib\site-packages\numpy\lib\tests\__init__.py

c:\python37\lib\site-packages\numpy\linalg\__init__.py

c:\python37\lib\site-packages\numpy\linalg\tests\__init__.py

c:\python37\lib\site-packages\numpy\ma\__init__.py

c:\python37\lib\site-packages\numpy\ma\tests\__init__.py

c:\python37\lib\site-packages\numpy\matrixlib\__init__.py

c:\python37\lib\site-packages\numpy\matrixlib\tests\__init__.py

c:\python37\lib\site-packages\numpy\polynomial\__init__.py

c:\python37\lib\site-packages\numpy\polynomial\tests\__init__.py

c:\python37\lib\site-packages\numpy\random\__init__.py

c:\python37\lib\site-packages\numpy\random\tests\__init__.py

c:\python37\lib\site-packages\numpy\testing\__init__.py

c:\python37\lib\site-packages\numpy\testing\_private\__init__.py

c:\python37\lib\site-packages\numpy\testing\tests\__init__.py

c:\python37\lib\site-packages\numpy\tests\__init__.py

*/

}

统计一下文件个数,分为两个版本,Go版和Python版

package main

import (

"fmt"

"os"

"path/filepath"

"strings"

"time"

)

func main() {

start_time := time.Now().UnixNano()

//下面我们来统计一下,c:\python37下面有多少个__init__.py文件,有多少个py文件,有多少个不是py文件的文件,有多少个目录

init_py_file := 0

py_file := 0

not_py_file := 0

dir := 0

walkFn := func(path string, info os.FileInfo, err error) error {

filename := info.Name()

is_dir := info.IsDir()

if strings.HasSuffix(filename, "__init__.py") {

//如果文件是以__init__.py结尾的话, 别忘了py_file也要++

init_py_file++

py_file++

} else if strings.HasSuffix(filename, ".py") {

//以.py结尾的话

py_file++

} else if is_dir {

//如果是目录的话

dir++

} else {

//既不是py结尾,也不是目录的话

not_py_file++

}

//这里我们直接返回nil即可

return nil

}

//那么开始遍历,会对遍历的每一个内容都交给walkFn进行处理

err := filepath.Walk(`c:\python37`, walkFn)

if err != nil {

fmt.Println("err =", err)

}

//打印相应的个数

fmt.Println(fmt.Sprintf("__init__.py文件个数:%d,py文件个数:%d,不是py文件的文件个数:%d,目录个数:%d", init_py_file, py_file, not_py_file, dir))

/*

__init__.py文件个数:1965,py文件个数:11911,不是py文件的文件个数:23050,目录个数:7685

*/

end_time := time.Now().UnixNano()

fmt.Println("总用时:", (end_time-start_time)/1e9) // 总用时: 4

}

再来看看Python版本的

from pathlib import Path

import os

import time

start_time = time.perf_counter()

init_py_file = 0

py_file = 0

not_py_file = 0

dir_ = 0

p = Path(r"c:\python37")

for file in p.rglob("*"):

if str(file).endswith("__init__.py"):

init_py_file += 1

py_file += 1

elif str(file).endswith(".py"):

py_file += 1

elif os.path.isdir(str(file)):

dir_ += 1

else:

not_py_file += 1

end_time = time.perf_counter()

print(f"__init__.py文件个数:{init_py_file},py文件个数:{py_file},不是py文件的文件个数:{not_py_file},目录个数:{dir_}")

# __init__.py文件个数:1965,py文件个数:11911,不是py文件的文件个数:23050,目录个数:7684

print(f"总用时:{end_time - start_time}")

# 总用时:3.695507357

总结:两者之间效率基本上是一样的,代码量的话,由于golang的{}多占了一行,并且如果不考虑if err != nil之类的话,代码量也基本差不多。但是我们比较一下结果的话,其他的是一样的,只有目录的个数不一样,Go的结果貌似比Python多了一个,这是因为,我们递归遍历的是c:\python37。在Go中,把c:\python37这个目录本身也给算进去了,而Python没有。所以其他的结果是一致的,但是目录个数的话,Go算出来会比Python多一个。当然仔细观察结果的话,稍加思考就能发现原因,这里程序就不再演示了,可以找一个文件或目录数量比较少的打印一下,会发现Python没有把最外层的目录打印出来,打印都是指定目录里面的内容。

package main

import (

"fmt"

"os"

"path/filepath"

)

func main() {

walkFn := func(path string, info os.FileInfo, err error) error {

is_dir := info.IsDir()

if is_dir {

//如果是目录,那么我们就跳过,不做处理

fmt.Println(fmt.Sprintf("%s是目录,已经跳过", path))

return filepath.SkipDir

}

return nil

}

//那么开始遍历,会对遍历的每一个内容都交给walkFn进行处理

err := filepath.Walk(`c:\python37`, walkFn)

if err != nil {

fmt.Println("err =", err)

}

/*

c:\python37是目录,已经跳过

*/

//可以发现,上来就跳过了,跳过是指整个目录跳过,目录里面有什么也不再关心了

//也可以得出,Go是会处理指定的目录,而Python不会,Python只处理指定目录里面的内容

}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30114439/article/details/112935200

智能推荐

Tomcat系列3-启动阶段源码分析_attribute "autodeploy" was already specified for e-程序员宅基地

文章浏览阅读187次。Tomcat的初始化流程结束后,就进去Tomcat各组件启动流程。初始化方法是在Bootstrap的main方法中的daemon.load(args),启动就是它后续的 daemon.start()。这个方法调用的是Catalina的start方法。1.Catalina public void start() { log.info("Catalina--------start..._attribute "autodeploy" was already specified for element "host

ES6——let、const和var的用法和区别_es6 varlet和const的区别-程序员宅基地

文章浏览阅读1.2k次,点赞3次,收藏7次。ES6—let、const和var的区别ES6 新增了let命令,用来声明变量,新增了const命令,用来声明常量,它的用法类似于var。let a = 1;var b = 2;const PI = 3.14;主要区别块级作用域//let声明的变量和const声明的常量有块级作用域,var声明的变量则只有函数作用域{ let a = 1; const PI = 3.14;..._es6 varlet和const的区别

什么是p99_p99是什么意思-程序员宅基地

文章浏览阅读3k次。p99表示过去10s内最慢的1%请求的平均延迟_p99是什么意思

史上最全采样方法详细解读与代码实现_gibbs采样算法代码-程序员宅基地

文章浏览阅读2.8k次,点赞2次,收藏6次。项目github地址:bitcarmanlee easy-algorithm-interview-and-practice欢迎大家star,留言,一起学习进步1.什么是采样在信号系统、数字信号处理中,采样是每隔一定的时间测量一次声音信号的幅值,把时间连续的,模拟信号转换成时间离散、幅值连续的采样信号。如果采样的时间间隔相等,这种采样称为均匀采样。在计算机系统中,有一个重要的问题就是给定一个概率分布p(x) , 我们如何在计算机中生成它的样本。平时我们接触比较多的场景是,给定一堆样本数据,求出这堆_gibbs采样算法代码

xctf-ics05_i‘′‘s5fct.′(xcg)-程序员宅基地

文章浏览阅读378次。xctf里面的一道web题ics05这道题给了提示:其他破坏者会利用工控云管理系统设备维护中心的后门入侵系统既然说了是设备维护中心的漏洞,打开设备维护中心,什么东西也没有,查看源码也没有啥东西。这时候瞎点,点到了网页上面的导航上 云平台设备维护中心发现有变化。发现page的值会显示出来。将page的参数改成index.php发现页面显示ok,改成其他的(比如flag.php)页面啥都没显..._i‘′‘s5fct.′(xcg)

测试用例的划分方法_研发云中对测试用例的类型的划分主要是基于-程序员宅基地

文章浏览阅读1k次。等价类划分等价类划分的概念 等价类划分法是将所有程序的输入域划分成若干个子集合(等价类),然后从每一个子集合中选取少数具有代表性的数据作为测试的输入数据 在该子集合中,所有的输入数据对于揭露软件中的错误都是等效的 等价类划分有效等价类(正面,不会报错)和无效等价类(负面,抛出错误)等价类划分法的场景:当测试需要数据量过大,且数据操作可以分类时进行等价类划分边界值分析法1:定义:边界值分析法是对等价类划分法的一个补充,边界值一般都是从等价类的边缘值去寻找2:原则..._研发云中对测试用例的类型的划分主要是基于

随便推点

jdk9,Java运行环境9,jdk-9.0.4_windows-x64_bin_java9.0_win64-程序员宅基地

文章浏览阅读712次。jdk9,Java运行环境9,jdk-9.0.4_windows-x64_bin链接:https://pan.baidu.com/s/1HpL5JqWW-E5GN938TR9edw提取码:8888复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V5的分享_java9.0_win64

Cesium学习(1)--geoserver+cesium创建离线环境下的web三维球_cesium+geoserver-程序员宅基地

文章浏览阅读8.5k次,点赞2次,收藏26次。基于geoserver搭建离线web球环境,采用cesium1.25版本,win10环境搭建,供大家参考。_cesium+geoserver

一文看懂数据库原理-程序员宅基地

文章浏览阅读2.8w次,点赞24次,收藏118次。一提到关系型数据库,我禁不住想:有些东西被忽视了。关系型数据库无处不在,而且种类繁多,从小巧实用的 SQLite 到强大的 Teradata 。但很少有文章讲解数据库是如何工作的。你可以自己谷歌/百度一下『关系型数据库原理』,看看结果多么的稀少【译者注:百度为您找到相关结果约1,850,000个…】 ,而且找到的那些文章都很短。现在如果你查找最近时髦的技术(大数据、NoSQL或JavaScript..._数据库原理

Best-First求解八数码问题_best-first算法例题-程序员宅基地

文章浏览阅读2.1k次。Best-First求解八数码问题。_best-first算法例题

Docker容器之Docker Compose详解_compose does not use swarm mode to deploy services-程序员宅基地

文章浏览阅读3.6k次。Docker Compose是一款容器编排工具,Compose是在一台机器上管理多个容器。Compose 是 Docker 容器进行编排的工具,定义和运行多容器的应用,可以一条命令启动多个容器,使用Docker Compose不再需要使用shell脚本来启动容器。_compose does not use swarm mode to deploy services to multiple nodes in a sw

vue2.0在PC端图片放大预览,始终保持在浏览器中间位置操作_vue图片预览插件pc端-程序员宅基地

文章浏览阅读4.7k次。通常放大图片预览无非是加一个遮罩层,然后让图片以一定的宽高显示。但是在实际中我们可能有像试卷一样每道题都有图片,只要点击都能预览,由于题很多,可就很难保证图片永远在可视区域中间位置显示,所以我们得通过js做一些处理:.img-show-mask { width: 100%; height: 100%; position: absolute; left: 0; ..._vue图片预览插件pc端