文章目錄
- 文件操作
- 基本介紹
- 普通的文件操作方式(os包)
- 帶緩沖的文件操作方式(bufio包)
- 文件拷貝操作(io包)
- 命令行參數
- 基本介紹
- 解析命令行參數(flag包)
- JSON
- 基本介紹
- JSON序列化
- JSON反序列化
文件操作
基本介紹
基本介紹
- 文件操作是指對計算機文件進行讀取、寫入、修改、刪除和移動等操作的過程,它可以用于讀取配置文件、存儲日志、處理用戶上傳的文件等,Go中主要通過os和bufio包提供文件操作功能。
- 文件在程序中是以流的形式進行操作的,我們把數據在數據源(文件)和程序(內存)之間經歷的路徑叫做流。其中數據從數據源到程序的路徑叫做輸入流,數據從程序到數據源的路徑叫做輸出流。
文件流示意圖如下:
普通的文件操作方式(os包)
os包介紹
在os包中,File類型代表一個打開的文件,其封裝了與文件相關的操作和屬性。File結構體的定義如下:
type File struct {*file // os specific
}
File結構體中以*type
的方式嵌套了file類型的匿名結構體指針,實際文件的屬性信息都存儲在file結構體中。file結構體的定義如下:
type file struct {pfd poll.FDname stringdirinfo atomic.Pointer[dirInfo] // nil unless directory being readnonblock bool // whether we set nonblocking modestdoutOrErr bool // whether this is stdout or stderrappendMode bool // whether file is opened for appending
}
file結構體各字段說明:
- pfd:用于與底層的操作系統文件描述符進行交互。
- name:表示文件的名稱(包括路徑)。
- dirinfo:用于在讀取目錄時緩存目錄的信息(打開的文件是目錄時被使用)。
- nonblock:表示文件是否設置為非阻塞模式。
- stdoutOrErr:表示文件是否是標準輸出或標準錯誤。
- appendMode:表示文件是否以追加模式打開。
每一個打開的文件都對應一個文件描述符,file結構體中的pfd是poll.FD類型的,實際文件對應的文件描述符就存儲在poll.FD結構體的Sysfd字段中。FD結構體的定義如下:
type FD struct {// Lock sysfd and serialize access to Read and Write methods.fdmu fdMutex// System file descriptor. Immutable until Close.Sysfd int// Platform dependent state of the file descriptor.SysFile// I/O poller.pd pollDesc// Semaphore signaled when file is closed.csema uint32// Non-zero if this file has been set to blocking mode.isBlocking uint32// Whether this is a streaming descriptor, as opposed to a// packet-based descriptor like a UDP socket. Immutable.IsStream bool// Whether a zero byte read indicates EOF. This is false for a// message based socket connection.ZeroReadIsEOF bool// Whether this is a file rather than a network socket.isFile bool
}
打開文件
在os包中,使用OpenFile函數打開文件,該函數的函數原型如下:
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
參數說明:
- name:表示需要打開的文件名稱(包括路徑)。
- flag:表示打開文件的方式。
- perm:表示新創建文件的權限,通常設置為0666(表示任何人都可讀寫,不可執行)。
返回值說明:
- file:如果打開文件成功,將返回文件對應的File結構體。
- err:如果打開文件過程中出錯,將返回非nil的錯誤值。
打開文件的方式可以使用以下標注之一或它們的組合。如下:
參數選項 | 含義 |
---|---|
O_RDONLY | 以只讀方式打開文件 |
O_WRONLY | 以只寫方式打開文件 |
O_RDWR | 以讀寫方式打開文件 |
O_APPEND | 以追加的方式打開文件 |
O_CREATE | 如果文件不存在,則創建文件 |
O_EXCL | 與O_CREATE一起使用,確保創建新文件時不會覆蓋現有文件 |
O_SYNC | 在每次寫入操作后同步文件內容到磁盤 |
O_TRUNC | 如果文件已存在,將截斷文件為零長度 |
打開文件示例如下:
package mainimport ("fmt""os"
)func main() {name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`// 打開文件file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0666)if err != nil {fmt.Printf("open file error, err = %v\n", err)return}fmt.Printf("open file success, fd = %v\n", file.Fd()) // open file success, fd = 420
}
說明一下:
- 通過File結構體的Fd方法,可以獲取該文件對應的文件描述符。文件的文件描述符由底層操作系統分配,每次打開文件時分配的文件描述符可能不同。
關閉文件
在os包中,使用File結構體的Close方法關閉文件,該方法的原型如下:
func (f *File) Close() error
返回值說明:
- 關閉文件成功返回nil,否則返回非nil的錯誤值。
關閉文件示例如下:
package mainimport ("fmt""os"
)func main() {name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`// 1、打開文件file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0666)if err != nil {fmt.Printf("open file error, err = %v\n", err)return}// 2、延遲關閉文件defer file.Close()
}
說明一下:
- 文件操作完畢后需要及時調用Close方法對文件進行關閉,避免造成文件描述符泄露。
- 通常利用defer機制對文件進行延遲關閉,在defer語句之后仍然可以操作文件,文件將會在函數執行完畢后自動關閉。
獲取文件屬性信息
在os包中,使用File結構體的Stat方法獲取文件的屬性信息,該方法的原型如下:
func (f *File) Stat() (fi FileInfo, err error)
返回值說明:
- fi:如果方法調用成功,將返回文件的屬性信息。
- err:如果方法調用過程中出錯,將返回非nil的錯誤值。
Stat方法獲取到的文件信息FileInfo是一個接口類型,該類型的定義如下:
type FileInfo interface {Name() string // base name of the fileSize() int64 // length in bytes for regular files; system-dependent for othersMode() FileMode // file mode bitsModTime() time.Time // modification timeIsDir() bool // abbreviation for Mode().IsDir()Sys() any // underlying data source (can return nil)
}
FileInfo接口中各方法說明:
- Name方法:返回文件的基本名稱(不包含路徑)。
- Size方法:返回文件的大小。
- Mode方法:返回文件的權限和模式位信息。
- ModTime方法:返回文件最后一次修改時間。
- IsDir方法:判斷文件是否是一個目錄。
- Sys方法:返回底層數據源,通常是操作系統特定的文件信息(可能返回nil)。
獲取文件屬性信息示例如下:
package mainimport ("fmt""os"
)func main() {name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`// 1、打開文件file, err := os.OpenFile(name, os.O_RDONLY, 0666)if err != nil {if os.IsNotExist(err) {fmt.Println("warning: file not exists...")} else {fmt.Printf("open file error, err = %v\n", err)}return}// 2、延遲關閉文件defer file.Close()// 3、獲取文件屬性信息fi, err := file.Stat()if err != nil {fmt.Printf("get file info error, err = %v\n", err)return}fmt.Printf("file name = %v\n", fi.Name()) // file name = data.txtfmt.Printf("file size = %v\n", fi.Size()) // file size = 240fmt.Printf("file mode = %v\n", fi.Mode()) // file mode = -rw-rw-rw-fmt.Printf("file modTime = %v\n", fi.ModTime()) // file modTime = 2024-05-09 17:27:33.1530703 +0800 CSTfmt.Printf("file isDir = %v\n", fi.IsDir()) // file isDir = falsefmt.Printf("file sys = %v\n", fi.Sys()) // file sys = &{32 {1262805282 31105508} {690243707 31105523} {521554895 31105523} 0 240}
}
說明一下:
- os包中的IsNotExist函數返回一個bool值,表示傳入的錯誤值是否表示文件或目錄不存在。
- os包中也提供了單獨的Stat函數用于獲取文件的屬性信息,調用時傳入文件名稱(包括路徑)即可。
寫文件
在os包中,使用File結構體的Write方法將指定內容寫入到文件中,該方法的原型如下:
func (f *File) Write(b []byte) (n int, err error)
參數說明:
- b:表示要寫入文件的數據。
返回值說明:
- n:表示成功寫入文件的字節數。
- err:如果寫入過程中出錯,將返回非nil的錯誤值。
寫文件示例如下:
package mainimport ("fmt""os""strconv"
)func main() {name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`// 1、打開文件file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0666)if err != nil {fmt.Printf("open file error, err = %v\n", err)return}// 2、延遲關閉文件defer file.Close()// 3、寫文件var str stringfor i := 0; i < 10; i++ {str += "Hello File(os package)" + strconv.Itoa(i) + "\n"}count, err := file.Write([]byte(str))if err != nil {fmt.Printf("write file error, err = %v\n", err)return}fmt.Printf("write %d bytes data to data.txt\n", count) // write 240 bytes data to data.txt
}
運行程序后可以看到數據被成功寫入文件。如下:
讀文件
在os包中,使用File結構體的Read方法讀取文件中的內容,該方法的原型如下:
func (f *File) Read(b []byte) (n int, err error)
參數說明:
- b:輸出型參數,用于存儲從文件中讀取到的數據。
返回值說明:
- n:表示成功讀取到的字節數。
- err:如果讀取過程中出錯,將返回非nil的錯誤值。
讀文件示例如下:
package mainimport ("fmt""os"
)func main() {name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\NormalOperation\data.txt`// 1、打開文件file, err := os.OpenFile(name, os.O_RDONLY, 0666)if err != nil {fmt.Printf("open file error, err = %v\n", err)return}// 2、延遲關閉文件defer file.Close()// 3、獲取文件大小fileInfo, err := file.Stat()if err != nil {fmt.Printf("get file info error, err = %v\n", err)return}fileSize := fileInfo.Size()// 4、讀文件buffer := make([]byte, fileSize)count, err := file.Read(buffer)if err != nil {fmt.Printf("read file error, err = %v\n", err)return}fmt.Printf("file size = %d, read count = %d\n", fileSize, count)fmt.Printf("file content:\n%s\n", string(buffer))
}
運行程序后可以看到文件中的數據被成功讀取出來。如下:
其他函數和方法
在os包中,常用的打開文件獲取File對象的函數如下:
函數名 | 功能 |
---|---|
OpenFile | 打開文件,可以指明打開文件的方式和新創建文件的權限 |
Open | 以只讀模式打開文件 |
Create | 以0666權限創建并打開文件,如果文件已存在會將其截斷 |
在os包中,常用的File結構體提供的文件操作方法如下:
方法名 | 功能 |
---|---|
Name | 獲取文件名稱(包括路徑) |
Stat | 獲取文件屬性信息 |
Fd | 獲取文件對應的文件描述符 |
Read | 從當前位置開始讀取文件數據 |
ReadAt | 從指定位置開始讀取文件數據 |
Write | 從當前位置開始向文件寫入數據 |
WriteString | 從當前位置開始向文件寫入一個字符串 |
WriteAt | 從指定位置開始向文件寫入數據 |
Seek | 設置下一次文件的讀寫位置 |
Close | 關閉文件 |
帶緩沖的文件操作方式(bufio包)
bufio包介紹
- bufio包中的Reader和Writer類型提供了帶緩沖的讀寫功能,可以搭配os包一起使用來實現文件的帶緩沖讀寫。
Reader結構體的定義如下:
type Reader struct {buf []byterd io.Reader // reader provided by the clientr, w int // buf read and write positionserr errorlastByte int // last byte read for UnreadByte; -1 means invalidlastRuneSize int // size of last rune read for UnreadRune; -1 means invalid
}
Reader結構體各字段說明:
- buf:內部緩沖區,用于臨時存儲從底層io.Reader讀取到的數據。
- rd:創建Reader對象時提供的io.Reader對象,用于讀取數據。
- r:緩沖區中的讀取位置,表示下一個要讀取的字節位置。
- w:緩沖區中的寫入位置,表示下一個要寫入的字節位置。
- err:存儲讀取數據過程中發生的錯誤。
- lastByte:上一次讀取的字節,用于UnreadByte方法,-1表示無效。
- lastRuneSize:上一次讀取的Unicode字符大小,用于UnreadRune方法,-1表示無效。
Reader結構體常用的方法如下:
方法名 | 功能 |
---|---|
Read | 從緩沖區中讀取數據到指定的字節切片中 |
ReadString | 從緩沖區中讀取數據到字符串中,直到遇到指定的分隔符 |
ReadLine | 從緩沖區讀取一行數據,返回的字節切片包含行尾的換行符 |
Writer結構體的定義如下:
type Writer struct {err errorbuf []byten intwr io.Writer
}
Writer結構體各字段說明:
- err:存儲寫入數據過程中發生的錯誤。
- buf:內部緩沖區,用于臨時存儲需要寫入到底層io.Reader的數據。
- n:緩沖區中的有效數據長度,表示待寫入的字節數。
- wr:創建Writer對象時提供的io.Writer對象,用于寫入數據。
Writer結構體常用的方法如下:
方法名 | 功能 |
---|---|
Write | 將字節切片中的數據寫入緩沖區 |
WriteString | 將字符串中的數據寫入緩沖區 |
Flush | 將緩沖區中的數據刷新到底層的io.Writer |
說明一下:
- Reader結構體中的lastByte字段,用于支持UnreadByte方法,該方法用于將最后讀取的字節放回緩沖區。lastRuneSize字段用于支持UnreadRune方法,該方法用于將最后讀取的Unicode字符放回緩沖區。
- Writer結構體中不需要記錄下一次緩沖區的讀取和寫入位置,因為Writer緩沖區的寫入操作是順序進行的,不需要回退或隨機訪問緩沖區中的數據,而只有當緩沖區滿或調用Flush方法時才會讀取緩沖區中的數據,將其刷新到底層的io.Writer中,每次刷新都會讀取整個緩沖區中的數據。
寫文件
要使用bufio包對文件進行寫入操作,首先需要創建出Writer對象,bufio包中提供了兩個用于創建Writer對象的函數,它們的函數原型如下:
func NewWriter(w io.Writer) *Writer
func NewWriterSize(w io.Writer, size int) *Writer
參數說明:
- w:創建Writer對象時提供的io.Writer對象,用于寫入數據。
- size:表示創建的Writer對象的緩沖區大小,以字節為單位。
返回值說明:
- 返回所創建的Writer對象的指針,該對象具有指定大小的緩沖區,如果使用NewWriter函數創建Writer對象,那么緩沖區大小默認為4096字節。
使用NewWriter或NewWriterSize函數創建Writer對象時,都需要提供一個io.Writer類型的對象。io.Writer本質是io包中的一個接口類型,其定義如下:
type Writer interface {Write(p []byte) (n int, err error)
}
io.Writer接口中只定義了一個Write方法,因此所有實現了該Write方法的類型都可以傳遞給io.Writer接口。而os包中的File結構體提供的Write方法,恰好與io.Writer接口中的Write方法簽名一致,因此File對象可以傳遞給io.Writer接口。File結構體提供的Write方法如下:
func (f *File) Write(b []byte) (n int, err error)
當bufio.Writer刷新底層緩沖區時,會回調File對象的Write方法,將緩沖區中的數據寫入到文件中,完成文件的寫入操作。案例如下:
package mainimport ("bufio""fmt""os""strconv"
)func main() {name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\BufferedOperation\data.txt`// 1、打開文件file, err := os.OpenFile(name, os.O_WRONLY|os.O_CREATE, 0666)if err != nil {fmt.Printf("open file error, err = %v\n", err)return}// 2、延遲關閉文件defer file.Close()// 3、寫文件var str stringfor i := 0; i < 10; i++ {str += "Hello File(bufio package)" + strconv.Itoa(i) + "\n"}writer := bufio.NewWriter(file) // 創建Writercount, err := writer.Write([]byte(str))if err != nil {fmt.Printf("write file error, err = %v\n", err)return}writer.Flush() // 刷新緩沖區fmt.Printf("write %d bytes data to data.txt\n", count) // write 270 bytes data to data.txt
}
運行程序后可以看到數據被成功寫入文件。如下:
注意: 只有當Writer緩沖區滿或調用Flush方法時,才會將緩沖區中的數據刷新到底層的io.Writer中,因此在數據寫入Writer后需要Flush方法刷新緩沖區中的數據。
讀文件
要使用bufio包對文件進行讀取操作,首先需要創建出Reader對象,bufio包中提供了兩個用于創建Reader對象的函數,它們的函數原型如下:
func NewReader(rd io.Reader) *Reader
func NewReaderSize(rd io.Reader, size int) *Reader
參數說明:
- rd:創建Reader對象時提供的io.Reader對象,用于讀取數據。
- size:表示創建的Reader對象的緩沖區大小,以字節為單位。
返回值說明:
- 返回所創建的Reader對象的指針,該對象具有指定大小的緩沖區,如果使用NewReader函數創建Reader對象,那么緩沖區大小默認為4096字節。
使用NewReader或NewReaderSize函數創建Reader對象時,都需要提供一個io.Reader類型的對象。io.Reader本質是io包中的一個接口類型,其定義如下:
type Reader interface {Read(p []byte) (n int, err error)
}
io.Reader接口中只定義了一個Read方法,因此所有實現了該Read方法的類型都可以傳遞給io.Reader接口。而os包中的File結構體提供的Read方法,恰好與io.Reader接口中的Read方法簽名一致,因此File對象可以傳遞給io.Reader接口。File結構體提供的Read方法如下:
func (f *File) Read(b []byte) (n int, err error)
當bufio.Reader讀取文件時,會回調File對象的Read方法,將文件中的數據讀取到緩沖區中,完成文件的讀取操作。案例如下:
package mainimport ("bufio""fmt""os"
)func main() {name := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\BufferedOperation\data.txt`// 1、打開文件file, err := os.OpenFile(name, os.O_RDONLY, 0666)if err != nil {fmt.Printf("open file error, err = %v\n", err)return}// 2、延遲關閉文件defer file.Close()// 3、獲取文件大小fileInfo, err := file.Stat()if err != nil {fmt.Printf("get file info error, err = %v\n", err)return}fileSize := fileInfo.Size()// 4、讀文件reader := bufio.NewReader(file) // 創建Readerbuffer := make([]byte, fileSize)count, err := reader.Read(buffer)if err != nil {fmt.Printf("read file error, err = %v\n", err)return}fmt.Printf("file size = %d, read count = %d\n", fileSize, count)fmt.Printf("file content:\n%s\n", string(buffer))
}
運行程序后可以看到文件中的數據被成功讀取出來。如下:
文件拷貝操作(io包)
io包介紹
在io包中,使用Copy函數能夠將數據從一個io.Reader拷貝到一個io.Writer中,該函數的函數原型如下:
func Copy(dst Writer, src Reader) (written int64, err error)
參數說明:
- dst:表示將拷貝到的數據寫入到該io.Writer中。
- src:表示從該io.Reader中拷貝數據。
返回值說明:
- written:返回成功拷貝的字節數。
- err:如果拷貝過程中出錯,將返回非nil的錯誤值。
拷貝文件
前面已經介紹過,io.Reader和io.Writer本質都是io包中的接口類型,os包中的File結構體對這兩個接口進行了實現,因此在使用io.Copy函數拷貝文件時,只需傳入src文件和dst文件的File對象即可。案例如下:
package mainimport ("fmt""io""os"
)func CopyFile(dstName string, srcName string) (err error) {// 1、以讀方式打開源文件srcFile, err := os.OpenFile(srcName, os.O_RDONLY, 0666)if err != nil {fmt.Printf("open src file error, err = %v\n", err)return}defer srcFile.Close()// 2、以寫方式打開目標文件dstFile, err := os.OpenFile(dstName, os.O_WRONLY|os.O_CREATE, 0666)if err != nil {fmt.Printf("open dst file error, err = %v\n", err)return}defer dstFile.Close()// 3、進行文件拷貝count, err := io.Copy(dstFile, srcFile)if err != nil {fmt.Printf("copy file error, err = %v\n", err)return}fmt.Printf("copy file success, copy size = %d\n", count) // copy file success, copy size = 250return
}func main() {srcName := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\CopyOperation\src.txt`dstName := `D:\github\Golang-topics\src\go_code\FileOperation\FileOperation\CopyOperation\dst.txt`err := CopyFile(dstName, srcName)if err != nil {fmt.Printf("copy file error, err = %v\n", err)}
}
運行程序后可以看到成功完成了文件的拷貝操作。如下:
命令行參數
基本介紹
基本介紹
- 命令行參數是在運行程序時通過命令行傳遞給程序的參數,在Go中可以使用os包的Args變量來訪問命令行參數。
- os.Args是一個字符串切片,其中第一個元素是程序本身的名稱,隨后的元素依次是傳遞給程序的命令行參數。
使用案例如下:
package mainimport ("fmt""os"
)func main() {fmt.Printf("os.Args type = %T\n", os.Args) // os.Args type = []stringfor index, value := range os.Args {fmt.Printf("args[%d] = %v\n", index, value)}
}
運行上述程序時指明命令行參數,可以看到命令行參數被逐一輸出。如下:
解析命令行參數(flag包)
flag包介紹
- 通過os包的Args變量雖然可以訪問命令行參數,但對參數的解析不是特別方便,比如各個參數的含義定義后要求嚴格的輸入順序。
- flag包是Go標準庫中的一個包,通過flag包可以輕松定義和解析命令行參數,并且參數的輸入順序可以隨意。
flag包中常用的函數如下:
函數名 | 功能 |
---|---|
StringVar | 用于定義一個string類型的命令行參數 |
IntVar | 用于定義一個int類型的命令行參數 |
BoolVar | 用于定義一個bool類型的命令行參數 |
Parse | 用于解析命令行參數,將命令行參數的值賦給相應的變量 |
其中StringVar、IntVar和BoolVar函數都有四個參數,沒有返回值。各個參數的含義如下:
- 第一個參數:指向對應類型變量的指針,用于存儲命令行參數的值。
- 第二個參數:命令行參數的名稱。
- 第三個參數:命令行參數的默認值,用戶未輸入該命令行參數時采用。
- 第四個參數:命令行參數的描述信息。
解析命令行參數
例如在運行mysql命令連接MySQL服務器時,需要通過命令行參數指明用戶名、密碼、服務端IP地址和端口號等。借助flag包可以按如下方式實現:
package mainimport ("flag""fmt"
)func main() {var user, psw, ip stringvar port intflag.StringVar(&user, "u", "root", "用戶名")flag.StringVar(&psw, "p", "000000", "密碼")flag.StringVar(&ip, "h", "localhost", "IP地址")flag.IntVar(&port, "P", 3306, "端口號")flag.Parse() // 解析命令行參數fmt.Printf("user = %v\n", user)fmt.Printf("psw = %v\n", psw)fmt.Printf("ip = %v\n", ip)fmt.Printf("port = %v\n", port)
}
在運行程序時,需要通過-命令行參數名稱 命令行參數
的形式,依次指明各個命令行參數,如果輸入的命令行參數名稱未定義,則會輸出一個簡單的使用手冊。如下:
只有按照正確的格式指明命令行參數后程序才能正常運行,但各個命令行參數的指明順序可以隨意。對于未指明的命令行參數,將采用定義命令行參數時給定的默認值。如下:
注意: 在命令行參數定義完畢后,需要調用Parse函數解析命令行參數,這樣才能將命令行參數的值賦給相應的變量。
JSON
基本介紹
基本介紹
- JSON(JavaScript Object Notation)是一種輕量級的數據交換格式,常用于在網絡上傳輸數據,它最初是基于JavaScript語言的一個子集,但目前已經成為一種獨立于編程語言的數據格式。
- 不同的系統和平臺通過JSON可以方便地交換和共享數據,無論其使用的是哪種編程語言,這使得JSON成為一種常用的數據交換格式,在Web開發、API設計和數據存儲中得到廣泛應用。
- JSON序列化指的是將數據轉換為JSON格式的過程,JSON反序列化指的是將JSON格式的數據轉換為原始數據的過程。
JSON使用人類可讀的文本來表示結構化數據,采用鍵值對的方式存儲數據,其由以下幾種數據類型組成:
- 對象:由一組無序的鍵值對組成,使用大括號{}表示。鍵是字符串,值可以是字符串、數字、布爾值、對象、數組或空值。
- 數組:由一組有序的值組成,使用中括號[]表示。值可以是字符串、數字、布爾值、對象、數組或空值。
- 字符串:由雙引號包圍的Unicode字符序列。
- 數字:整數或浮點數。
- 布爾值:true或false。
- 空值:null。
例如下面是一個簡單的JSON字符串:
{"name": "Alice","age": 12,"gender": "女","scores": [105,128,115]
}
JSON序列化
JSON序列化
在Go中,使用encoding/json包中的Marshal函數能夠對數據進行JSON序列化,該函數的函數原型如下:
func Marshal(v interface{}) ([]byte, error)
參數說明:
- v:需要進行JSON序列化的任意類型的數據。
返回值說明:
- 第一個返回值:表示JSON序列化成功后得到的JSON字符串。
- 第二個返回值:如果序列化過程中出錯,將返回非nil的錯誤值。
使用案例如下:
package mainimport ("encoding/json""fmt"
)type Student struct {Name string `json:"name"`Age int `json:"age"`Gender string `json:"gender"`Scores map[string]int `json:"scores"`
}func main() {var stu = Student{Name: "Alice",Age: 12,Gender: "女",Scores: map[string]int{"語文": 105,"數學": 128,"英語": 115,},}data, err := json.Marshal(stu)if err != nil {fmt.Printf("json serialize error, err = %v\n", err)return}fmt.Printf("json str = %s\n", string(data))
}
運行程序后可以看到序列化后的JSON字符串。如下:
說明一下: 通過結構體字段的Tag標簽,可以指定結構體各個字段在JSON序列化時的名稱,如果沒有指定則默認使用字段名。
JSON反序列化
JSON反序列化
在Go中,使用encoding/json包中的Unmarshal函數能夠將JSON字符串反序列化為原始數據,該函數的函數原型如下:
func Unmarshal(data []byte, v interface{}) error
參數說明:
- data:需要進行反序列化的JSON字符串。
- v:指向目標結構體或數據的指針,用于保存反序列化后的結果。
返回值說明:
- 反序列化成功返回nil,否則返回非nil的錯誤值。
使用案例如下:
package mainimport ("encoding/json""fmt"
)type Student struct {Name string `json:"name"`Age int `json:"age"`Gender string `json:"gender"`Scores []int `json:"scores"`
}func main() {var str = `{"name":"Alice","age":12,"gender":"女","scores":[105,128,115]}`var stu Studenterr := json.Unmarshal([]byte(str), &stu)if err != nil {fmt.Printf("json unserialize error, err = %v\n", err)return}fmt.Printf("stu = %v\n", stu)
}
運行程序后可以看到反序列化后的Student對象。如下:
注意: 要確保反序列化的數據類型與序列化前的數據類型一致,否則會反序列化失敗。