Go语言学习篇05

Go语言学习篇05

Golang 文件操作

文件简介

  • 基本介绍
    • 文件是数据源,数据库本质是文件
    • 文件在程序中是以流的形式来操作的

在这里插入图片描述

  • 流的概述
    • 流:数据在数据源(文件)和程序(内存)之间经历的路径
    • 输入流:数据从数据源(文件)到程序(内存)的路径
    • 输出流:数据从程序(内存)到数据源(文件)的路径

os.File封装了所有文件相关的操作,File是一个结构体

文件的使用

1)打开一个文件进行读写操作

os.Open(name string) (*File, error)

2)关闭一个文件

File.Close()

3)其它

file对象、file指针、file文件句柄 //3种叫法

打开和关闭文件

  • 文件是一个指针

func Open

func Open(name string) (file *File, err error)

Open打开一个文件用于读取。如果操作成功,返回的文件对象的方法可用于读取数据;对应的文件描述符具有O_RDONLY模式。如果出错,错误底层类型是*PathError。

func (*File) Close

func (f *File) Close() error

Close关闭文件f,使文件不能用于读写。它返回可能出现的错误。

案例

package main

import (
	"fmt"
	"os"
)

func main() {
    
    
	//file对象、file指针、file文件句柄
	var filePath string = "D:/axis.log"
	file, err := os.Open(filePath)
	if err != nil {
    
    
		fmt.Println("文件打开error:", err)
		return
	}
	//打开文件
	fmt.Println(file) //&{0xc000100780} file就是一个指针

	//关闭文件
	error := file.Close()
	if error != nil {
    
    
		fmt.Println("关闭文件error:", error)
	}
}

带缓冲的文件读取

1)读取文件的内容并显示在终端带缓冲区的方式,适用于大文件),使用os.Open, file.Close(),

bufio.NewReader(), reader.ReaderString 函数和方法

  • 缓冲:
    • 读一部分,处理一部分
    • 适用于所有大文件

代码

package main

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

func main() {
    
    
	file, error := os.Open("D:/axis.log")
	if error != nil {
    
    
		fmt.Println("文件打开失败,", error)
		return
	}
	defer file.Close()//延时机制
	//创建一个指针内型的reader
	//默认缓冲4096字节,读一部分,取一部分=缓冲
	reader := bufio.NewReader(file)

	for {
    
    
		str, err := reader.ReadString('\n')
		if err == io.EOF {
    
    
			fmt.Println("已达文件末尾")
			break
		}
		if err != nil {
    
    
			fmt.Println("读取过程中出现错误,", err)
			break
		}
		fmt.Print(str)
	}
	fmt.Println("文件读取结束...")
}

结果

2020-08-02 16:00:24,505 0      [           main] INFO  ClassPathXmlApplicationContext  - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@fb434: startup date [Sun Aug 02 16:00:24 CST 2020]; root of context hierarchy
2020-08-02 16:00:24,571 66     [           main] INFO  ry.xml.XmlBeanDefinitionReader  - Loading XML bean definitions from class path resource [applicationContext.xml]
已达文件末尾
文件读取结束...

一次性的文件读取

  • 适用于小文件

io/ioutil包下

func ReadFile

func ReadFile(filename string) ([]byte, error)

ReadFile 从filename指定的文件中读取数据并返回文件的内容。成功的调用返回的err为nil而非EOF。因为本函数定义为读取整个文件,它不会将读取返回的EOF视为应报告的错误

代码

package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
    
    
	bytes, error := ioutil.ReadFile("d:\axis.log")
	if error != nil {
    
    
		fmt.Println("文件读取出错,", error)
		return
	}
	fmt.Println(string(bytes))
}

结果

2020-08-02 16:00:24,505 0      [           main] INFO  ClassPathXmlApplicationContext  - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@fb434: startup date [Sun Aug 02 16:00:24 CST 2020]; root of context hierarchy
2020-08-02 16:00:24,571 66     [           main] INFO  ry.xml.XmlBeanDefinitionReader  - Loading XML bean definitions from class path resource [applicationContext.xml]


结论

  • ioutil.ReaderFile(path string) 不带缓冲,只适用于小文件

写文件操作

Constants

const (
    O_RDONLY int = syscall.O_RDONLY // 只读模式打开文件
    O_WRONLY int = syscall.O_WRONLY // 只写模式打开文件
    O_RDWR   int = syscall.O_RDWR   // 读写模式打开文件
    O_APPEND int = syscall.O_APPEND // 写操作时将数据附加到文件尾部
    O_CREATE int = syscall.O_CREAT  // 如果不存在将创建一个新文件
    O_EXCL   int = syscall.O_EXCL   // 和O_CREATE配合使用,文件必须不存在
    O_SYNC   int = syscall.O_SYNC   // 打开文件用于同步I/O
    O_TRUNC  int = syscall.O_TRUNC  // 如果可能,打开时清空文件
)

func OpenFile

func OpenFile(name string, flag int, perm FileMode) (file *File, err error)

OpenFile是一个更一般性的文件打开函数,大多数调用者都应用Open或Create代替本函数。它会使用指定的选项(如O_RDONLY等)、指定的模式(如0666等)打开指定名称的文件。如果操作成功,返回的文件对象可用于I/O。如果出错,错误底层类型是*PathError。

name是文件

flag是打开的方式

FileMode只在Unix、Linux有效

写文件新建01

  • 创建一个新文件,写入内容 5句"hello go"
    • os.Open
    • 使用带缓存的方式:bufio.NewWriter()

代码

package main

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

func main() {
    
    
	filePath := "d:/carter.txt"
	file, error := os.OpenFile(filePath, os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0666)

	if error != nil {
    
    
		fmt.Println("文件打开失败,", error)
		return
	}

	defer file.Close()

	//准备写入的内容
	str := "hello go"

	//带缓冲的写入
	writer := bufio.NewWriter(file)

	for i := 0; i < 5; i++ {
    
    
        //有些不能识别\n换行符
		writer.WriteString(str + strconv.Itoa(i) + "\r\n")
	}

	//writer是带缓存的
	//内容先写入缓存,使用Flush真正写入文件中
	//否则文件没有数据,数据还在缓存中
	writer.Flush()
	fmt.Println("文件写入成功...")
}

结果

hello go0
hello go1
hello go2
hello go3
hello go4

结论

  • bufio.NewWriter是带缓存的
  • 内容先写入缓存,并没有写到数据源(文件)
  • 使用Flush( ),真正写入文件中

写文件覆盖02

1)已存在的文件,进行覆盖

  • 思路
    • 只写+清空:os.O_WRONLY | os.O_TRUNC
    • 换行:\r\n

写文件追加03

1)原先的文件上追加文字

  • 思路
    • 只写+追加:os.O_WRONLY | os.O_APPEND
    • 换行:\r\n

读写文件追加04

1)打开一个存在的文件,将原来的文件读出显示在终端,并追加5句"hello world"

  • 思路
    • 只读+追加:os.O_RDONLY | os.O_APPEND
    • 换行:\r\n

代码

package main

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

func showFile (file *os.File) {
    
    
	fmt.Println("文件读取中...")
	//读取源文件类型
	reader := bufio.NewReader(file)
	for {
    
    
		str, err := reader.ReadString('\n')
		if err == io.EOF {
    
    
			break
		}
		//显示在终端
		fmt.Print(str)
	}
}

func main() {
    
    
	filePath := "d:/carter.txt"
	file, error := os.OpenFile(filePath, os.O_RDONLY | os.O_APPEND, 0666)

	if error != nil {
    
    
		fmt.Println("文件打开失败,", error)
		return
	}

	defer file.Close()

	//显示文件
	showFile(file)

	//准备写入的内容
	str := "hello world"

	//带缓冲的写入
	writer := bufio.NewWriter(file)

	for i := 1; i < 5; i++ {
    
    
		writer.WriteString(str + strconv.Itoa(i) + "\r\n")
	}

	//writer是带缓存的
	//内容先写入缓存,使用Flush真正写入文件中
	//否则文件没有数据,数据还在缓存中
	writer.Flush()
	fmt.Println("OK~")
}

文件之间的读写

1)编写一个程序,将一个文件的内容,写入到另一个文件中。

注意:这两个文件已经存在

说明:

​ 使用ioutil.ReadFile 、 ioutil.WriteFile完成

  • 都是一次性的

在这里插入图片描述

案例2

  • 文件1—>文件2
    • 读:iouilt.ReadFile[一次性]
    • 打开:os.OpenFile()[带缓存]
    • 关闭:file.Close()
    • 写+追加:os.O_WRONLY | os.O_APPEND
    • bufio.NewWriter(name string)[带缓存]
    • 刷新缓存:writer.Flush()
package main

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

func main() {
    
    
	file1Path := "d:/axis.log"
	file2Path := "d:/carter.txt"

	//1、读取文件1
	//ioutil中是一次性的,不需要关闭文件
	data, error1 := ioutil.ReadFile(file1Path)
	if error1 != nil {
    
    
		fmt.Println("file1文件读取有误,error=", error1)
		return
	}

	//2、打开文件2(写+追加)
	//os中是带缓存的,需要Close()
	file2, error2 := os.OpenFile(file2Path, os.O_WRONLY | os.O_APPEND, 0666)
	if error2 != nil {
    
    
		fmt.Println("文件打开出错,", error2)
		return
	}
	defer file2.Close()//关闭文件资源

	//3、写文件
	writer := bufio.NewWriter(file2)
	length, error3 := writer.Write(data)
	fmt.Println("length:", length)
	if error3 != nil {
    
    
		fmt.Println("写入过程有误,", error3)
		return
	}

	//4、刷新缓存
	writer.Flush()
	fmt.Println("成功写入到carter.txt中")
}

文件是否存在?

  • os.Stat()函数
    • 返回的error是nil,说明文件(夹)是存在的
    • 返回的error是IsNotExist( ),说明文件(夹)是不存在的
    • 返回的是其它类型,说明文件(夹)不确定是否存在

文件是否存在的函数

package main

import (
	"fmt"
	"os"
)

func FileExists(filePath string) (bool, error)  {
    
    
	fileInfo, error := os.Stat(filePath)
	if error == nil {
    
    
		if fileInfo.IsDir() {
    
    
			fmt.Println("这是个文件夹...")
		}
		return true, nil
	}
	if os.IsNotExist(error) {
    
    
		return false, nil
	}
	return false, error
}

func main() {
    
    
	flag, err := FileExists("D:/222s")
	if flag {
    
    
		fmt.Println("文件存在...")
	} else if err == nil {
    
    
		fmt.Println("文件不存在...")
	} else {
    
    
		fmt.Println(err)
	}
}

拷贝图片

如果文件不存在,自己创建

func Copy

func Copy(dst Writer, src Reader) (written int64, err error)

src的数据拷贝到dst,直到在src上到达EOF或发生错误。返回拷贝的字节数和遇到的第一个错误。

对成功的调用,返回值err为nil而非EOF,因为Copy定义为从src读取直到EOF,它不会将读取到EOF视为应报告的错误。如果src实现了WriterTo接口,本函数会调用src.WriteTo(dst)进行拷贝;否则如果dst实现了ReaderFrom接口,本函数会调用dst.ReadFrom(src)进行拷贝。

代码

package main

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

//编写函数接收两个文件路径
func CopyFile(dstFileName string, srcFileName string) (written int64, err error) {
    
    
	srcFile, srcError := os.Open(srcFileName)
	if srcError != nil {
    
    
		fmt.Println("Error opening file,", srcError)
		return
	}
	defer srcFile.Close()//戒得关闭句柄
	//通过srcFile获取到Reader
	reader := bufio.NewReader(srcFile)
	//只写+创建
	dstFile, dstError := os.OpenFile(dstFileName, os.O_WRONLY | os.O_CREATE, 0666)
	if dstError != nil {
    
    
		fmt.Println("Error opening file,", dstError)
		return
	}
	defer dstFile.Close()//防止内存泄露
	//通过dstFileName获取到writer
	writer := bufio.NewWriter(dstFile)
	return io.Copy(writer, reader)//目标文件writer+源文件reader
}

func main() {
    
    
	srcFile := "C:/Users/Pictures/4K壁纸/美女.jpg"
	dstFile := "C:/Users/Desktop/abc.jpg"
	_, error := CopyFile(dstFile, srcFile)
	if error != nil{
    
    
		fmt.Println("Error Coping file,", error)
	} else {
    
    
		fmt.Println("Copy completed...")
	}
}

统计字符类型

1)统计英文、数字、空格和其它字符数量

说明:

​ 统计一个文件中含有的英文、数字、空格及其它字符数量

  • 思路
    • 打开一个文件
    • 创建带缓存的Reader
    • 每Reader一行进行一次统计
    • 将结果保存到结构体中

代码

package main

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

type CharCount struct {
    
    
	EnglishCount int
	NumberCount int
	SpaceCount int
	OtherCount int
}

func main() {
    
    
	filePath := "d:/carter.txt"
	file, error := os.Open(filePath)
	defer file.Close()
	if error != nil {
    
    
		fmt.Println("Error opening file,", error)
		return
	}

	var charCount CharCount

	reader := bufio.NewReader(file)

	//循环读取文件内容
	for {
    
    
		str, err := reader.ReadString('\n')//换行符为准,进行分隔
		if err == io.EOF {
    
    
			break
		}
		if err != nil {
    
    
			fmt.Println("文件读取错误...")
			break
		}
		//兼容中文字符
		strSlice := []rune(str)
		for _, value := range strSlice {
    
    
			switch {
    
    //注意:这个地方不要key,分支结构
			case value >= 'a' && value <= 'z':
				charCount.EnglishCount++
			case value >= 'A' && value <= 'Z':
				charCount.EnglishCount++
			case value == ' ' || value == '\t':
				charCount.SpaceCount++
			case value > '0' && value < '9':
				charCount.NumberCount++
			default:
				charCount.OtherCount++
			}
		}
	}
	fmt.Println("字母个数:", charCount.EnglishCount)
	fmt.Println("数字个数:", charCount.NumberCount)
	fmt.Println("空格个数:", charCount.SpaceCount)
	fmt.Println("其它字符个数:", charCount.OtherCount)
}

结果

字母个数: 4
数字个数: 4
空格个数: 4
其它字符个数: 5

结论

注意switch的分支用法

Args解析命令行参数

我们希望能够获取密令行输入的各种参数,该如何处理?

os.Args是一个string切片,按空格统计

代码

package main

import (
	"fmt"
	"os"
)

func main() {
    
    
	fmt.Println("参数个数:", len(os.Args))
	for index, value := range os.Args {
    
    
		fmt.Printf("args[%v]=%v\n", index, value)
	}
}

运行

D:\Work\Goland\Go\src\showComannd\main>go build -o test.exe main.go
D:\Work\Goland\Go\src\showComannd\main>test.exe d:/aaa/bbb/axis.log 88
参数个数: 3
args[0]=test.exe
args[1]=d:/aaa/bbb/axis.log
args[2]=88

flag包解析命令行参数

模板:

mysql -u carter -p 1234 -h localhost -P 3306

代码

package main

import (
	"flag"
	"fmt"
)

func main() {
    
    
	var username string
	var password string
	var host string
	var port int

	flag.StringVar(&username, "u", "", "获取用户名,默认为空")
	flag.StringVar(&password, "p", "", "获取密码,默认为空")
	flag.StringVar(&host, "h", "localhost", "主机默认是localhost")
	flag.IntVar(&port, "P", 3306, "端口默认3306")

	//必须调用该方法
	flag.Parse()

	//输出结果
	fmt.Printf("username=%v\n", username)
	fmt.Printf("password=%v\n", password)
	fmt.Printf("host=%v\n", host)
	fmt.Printf("port=%v\n", port)
}

结果

D:\Work\Goland\Go\src\showComannd\flag\main>main.exe -u carter -p 1122
username=carter
password=1122
host=localhost
port=3306

Golang Json篇

Json 基本介绍

1)JSON(JavaScript Object Notation)是一种轻量级的数据交换格式

2)JSON在2001年开始推广使用,是现如今的主流的数据格式

3)JSON易于机器解析和生成,并有效的提升网络传输效率

4)通常在网络传输时会将数据(结构体、map等序列化成json字符串,到接收方得到json字符串时,再反序列化,恢复成原来的数据类型

在这里插入图片描述

Json数据格式说明

在JS语言中,一切都是对象

在这里插入图片描述

Json序列化的使用

  • 介绍

Json序列化是指,将有key-value结构的数据类型(比如结构体、map、切片)序列化成json字符串的操作

  • 应用案例

将结构体、map和切片的序列化

  • 代码演示
package main

import (
	"encoding/json"
	"fmt"
)

// Define a structure
type Student struct {
    
    
	Name string `json:"name"`
	Age int	`json:"age"`
	Birthday string `json:"birthday"`
	Salary float64	`json:"salary"`
	Skill string	`json:"skill"`
}

func testStruct() {
    
    
	var stu Student = Student{
    
    
		Name:     "孙悟空",
		Age:      700,
		Birthday: "1211-11-12",
		Salary:   10000.50,
		Skill:    "筋斗云",
	}
	// Serialization
	bytes, error := json.Marshal(&stu)
	if error != nil {
    
    
		fmt.Println("Serialization error,error=", error)
		return
	}
	fmt.Println("Student序列化后的结果:", string(bytes))
}

func testMap() {
    
    
	// 1、Define a map
	var map01 map[string]interface{
    
    }
	// 2、Use map ,need to make
	map01 = make(map[string]interface{
    
    })
	map01["name"] = "唐僧"
	map01["sex"] = "男"
	map01["address"] = "东土大唐"
	data, error := json.Marshal(map01)
	if error != nil {
    
    
		fmt.Println("Serialization error,error=", error)
		return
	}
	fmt.Println("map序列化后的结果:", string(data))
}

// Slice contains multiple maps
func testSlice() {
    
    
	var slice []map[string]interface{
    
    }
	var map1 map[string]interface{
    
    }
	// Need to make before use
	map1 = make(map[string]interface{
    
    })
	map1["name"] = "carter"
	map1["age"] = 18
	map1["sex"] = "man"

	var map2 map[string]interface{
    
    }
	map2 = make(map[string]interface{
    
    })
	map2["name"] = "廖述幸"
	map2["age"] = 20
	map2["sex"] = "男"

	slice = append(slice, map1, map2)
	// Slice serialization
	data, error := json.Marshal(slice)
	if error != nil {
    
    
		fmt.Println("Serialization error,error=", error)
		return
	}
	fmt.Println("slice序列化后的结果:", string(data))
}

func main() {
    
    
	// 1、Structure serialization
	testStruct()
	// 2、Map serialization
	testMap()
	// 3、Slice serialization
	testSlice()
}
  • 结果
Student序列化后的结果: {
    
    "name":"孙悟空","age":700,"birthday":"1211-11-12","salary":10000.5,"skill":"筋斗云"}
map序列化后的结果: {
    
    "address":"东土大唐","name":"唐僧","sex":"男"}
slice序列化后的结果: [{
    
    "age":18,"name":"carter","sex":"man"},{
    
    "age":20,"name":"廖述幸","sex":"男"}]

基本数据类型Json序列化

  • 序列化后是本身,意义不大
  • 代码演示
package main

import (
	"encoding/json"
	"fmt"
)
func testBasicDataTypes() {
    
    
	var num float64 = 123.45
	data, error := json.Marshal(num)
	if error != nil {
    
    
		fmt.Println("Serialization error,error=", error)
		return
	}
	fmt.Println("num float64序列化后的结果:", string(data))
}
func main() {
    
    
	// Serialization of basic data types
	testBasicDataTypes()
}
  • 结果
num float64序列化后的结果: 123.45

反序列化

基本介绍

  • 介绍

Json反序列化是指:将Json字符串反序列化成对应的数据类型(比如结构体、map、切片)的操作

Json反序列化成 结构体、map、切片

  • 注意
    • 反序列化前后类型一致
    • Unmarshal中封装了make操作
    • json.Unmarshal([]byte(“序列化的值”), &类型)

代码

package main

import (
	"encoding/json"
	"fmt"
)
// Define a structure
type Student struct {
    
    
	Name string `json:"name"`
	Age int	`json:"age"`
	Birthday string `json:"birthday"`
	Salary float64	`json:"salary"`
	Skill string	`json:"skill"`
}

func unMarshalStruct() {
    
    
	str := `{"name":"孙悟空","age":700,"birthday":"1211-11-12","salary":10000.5,"skill":"筋斗云"}`
	//define a Student instance
	var stu Student
	// Parameter is pointer
	error := json.Unmarshal([]byte(str), &stu)
	if error != nil {
    
    
		fmt.Println("Struct反序列化失败,error", error)
		return
	}
	fmt.Println("Struct反序列化的结果:", stu)
}

func unMarshalMap() {
    
    
	map01 := `{"address":"东土大唐","name":"唐僧","sex":"男"}`
	//Need not to make, Unmarshal has make operate
	var mapResult map[string]interface{
    
    }
	error := json.Unmarshal([]byte(map01), &mapResult)
	if error != nil {
    
    
		fmt.Println("Map反序列化失败,error", error)
		return
	}
	fmt.Println("Map反序列化的结果:", mapResult)
}
func unMarshalSlice() {
    
    
	slice := `[{"age":18,"name":"carter","sex":"man"},{"age":20,"name":"廖述幸","sex":"男"}]`
	//Need not to make, Unmarshal has make operate
	var sliceResult []map[string]interface{
    
    }
	error := json.Unmarshal([]byte(slice), &sliceResult)
	if error != nil {
    
    
		fmt.Println("Slice反序列化失败,error", error)
		return
	}
	fmt.Println("Slice反序列化的结果:", sliceResult)
}

func main() {
    
    
	// 1、Unmarshal structure
	unMarshalStruct()
	// 2、Unmarshal map
	unMarshalMap()
	// 3、Unmarshal slice
	unMarshalSlice()
}

结果

Struct反序列化的结果: {
    
    孙悟空 700 1211-11-12 10000.5 筋斗云}
Map反序列化的结果: map[address:东土大唐 name:唐僧 sex:]
Slice反序列化的结果: [map[age:18 name:carter sex:man] map[age:20 name:廖述幸 sex:]]

猜你喜欢

转载自blog.csdn.net/IT_Carter/article/details/110801673