刘沙河 刘沙河
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希

花开半夏,半夏花开
首页
  • Go语言基础

    • 数据类型
    • 反射
    • Go指针
  • Go语言进阶

    • go泛型
    • go条件编译
    • cgo教程
    • Go协程调度原理及GPM模型
    • Go内存管理
    • Go垃圾回收机制
    • Go语言内存对齐
  • Go语言实现原理

    • channel 实现原理
    • slice 实现原理
    • map 实现原理
    • sync.Mutex 实现原理
    • 乐观锁CAS 实现原理
    • singlefight 实现原理
  • gin框架

    • gin中间件原理
    • gin路由原理
  • gorm

    • GORM介绍和使用
    • GORM_CURD操作指南
  • go测试

    • benchmark基准测试
    • pprof 性能分析
  • python进阶

    • Numpy&Pandas
    • celery分布式任务队列
  • Django

    • Django 常见命令
    • middleware中间件
    • Django缓存系统
    • Django信号系统
    • Django REST Framework
  • Flask

    • Flask基础知识总结
    • Flask-SQLAlchemy
  • 爬虫

    • aiohttp
    • scrapy框架
  • Mysql

    • Mysql存储引擎和索引
    • MySQL主从复制
    • Mysql读写分离
    • 数据库分库分表
    • Mysql锁
    • Mysql事务和MVCC原理
    • 分库分表带来的读扩散问题
  • Redis

    • redis基础和数据类型
    • redis主从架构
    • redis哨兵架构
    • redis集群模式
    • 如何保证缓存和数据库双写一致
    • redis底层数据结构
    • redis分布式锁
  • Elasticsearch

    • es基本概念
    • es基础语法
    • es倒排索引
  • etcd

    • Go操作etcd
    • Raft原理
    • etcd分布式锁
  • kafka

    • 消息队列MQ总结
    • kafka 概述及原理
    • kafka 消费问题记录
    • 零拷贝技术
    • kafka分区规范
  • RabbitMQ

    • rabbitMQ基础
    • Go操作rabbitmq
  • RocketMQ

    • 可靠消息队列 rocketMQ
  • Http&Https

    • http&https
    • TCP和UDP
    • Ping 原理
  • RPC

    • RPC初识
    • grpc初识和实现
  • gRPC

    • grpc 初识
    • grpc 上下文 metadata
    • grpc 健康检查
    • grpc keepalive
    • grpc 命名解析
    • grpc 中间件&拦截器
    • grpc 负载均衡
    • grpc 身份认证
    • grpc 超时重试
    • grpc 链路追踪
    • grpc-gw将gRPC转RESTfu api
    • grpc-gw自定义选项
  • protobuf

    • protobuf 进阶
    • protobuf 编码原理
  • Docker

    • Docker基础
    • Docker常用命令
    • Dockerfile
    • Docker-Compose
    • Docker多阶段构建
    • Docker Config 教程
    • Docker Swarm 教程
    • Docker Stack 教程
    • Docker Buildx 教程
  • k8s

    • k8s 基础概念
    • k8s 集群架构
    • k8s 工作负载
    • Pod 网络
    • Service 网络
    • 外部接入网络
    • 一张图搞懂k8s各种pod
    • k8s 存储抽象
    • mac快速启动k8s
    • 自制申威架构k8s-reloader
  • go-kit

    • go-kit初识
    • go-kit启动http服务
    • go-kit集成gin启动服务
    • go-kit集成grpc和protobuf
    • go-kit中间件
    • go-kit服务注册发现与负载均衡
    • go-kit限流和熔断
    • go-kit链路追踪
    • go-kit集成Prometheus
  • 设计模式

    • 初识设计模式
    • 创建型模式
    • 结构型模式
    • 行为模式
  • 数据结构

    • 时间轮
    • 堆、双向链表、环形队列
    • 队列:优先队列
    • 队列:延迟队列
  • 算法

    • 递归算法
    • 枚举算法
    • 动态规划
    • 回溯算法
    • 分治算法
    • 贪心算法
    • LRU和LFU
    • 一致性哈希
  • go语言基础

    • 反射
    • nethttp模块
    • Socket编程
    • 内置函数&库
    • Context
    • 正则表达式
    • 环境配置
    • GoPath和GoMod
    • 变量
    • 数据类型
    • 运算符
    • 数据类型相关操作
    • 基础语法
    • 函数&复合类型
    • go指针
    • 函数
    • 数组和切片
    • 结构体
    • 接口
    • 空结构体
    • 文件操作
      • 读文件
      • 写文件
    • 并发与通道
    • channel 原理和坑
  • go语言进阶

  • go语言实现原理

  • gin框架

  • gorm

  • go测试

  • Go语言
  • go语言基础
bigox
2021-03-31
目录

文件操作

  • 文件操作设计的I/O操作库
    • io -- 提供基本的接口
    • io/ioutil -- 封装了一些常用的接口
    • fmt -- 实现格式化IO. 类似c语言中的printf和scanf
    • bufio -- 实现缓存I/O

# io/ioutil

  • 读取文件目录 ReadDir(), 返回一个列表[]os.FileInfo, 列表中包含指定目录的目录信息

    type FileInfo interface{
      Name() string // 文件名称
      Size() int64  // 文件大小
      Mode() FileMode  //打开模式
      ModTime() time.Time  //文件修改时间
      IsDIr() bool   // 是否是目录
      Sys()  interface{}  // 基础数据源
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    • demo : 查看文件夹中所有文件, 并输出文件名

      package main
      
      import (
      	"fmt"
      	"io/ioutil"
      )
      
      func getFileName(filePath string)  {
      	dir, err := ioutil.ReadDir(filePath)
      	if err != nil {
      		fmt.Println(err)
      	}
      	for _,file := range dir{
      		fileName := file.Name()
      		fmt.Println(fileName)
      	}
      }
      
      
      func main() {
      	filePath := "../../"
      	getFileName(filePath)
      
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24

# path/filepath

  • Walk() 获取目录下所有文件和文件夹

    package main
    
    import (
    	"fmt"
    	"io/fs"
    	"path/filepath"
    )
    
    //walk() 获取指定目录下的所有文件和文件夹
    func WalkDir(dirPath string)   {
    	err := filepath.Walk(dirPath, func(path string, info fs.FileInfo, err error) error {
    		if info ==nil{
    			return err
    		}
    		if info.IsDir(){
    			return nil
    		}
    		fmt.Println(path)
    		return nil
    	})
    	if err != nil{
    		fmt.Printf("filepath.Walk() returned %v\n",err)
    	}
    }
    
    func main() {
    	WalkDir("./")
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

# OS

  • os.Makedir创建文件夹,需要指定权限
    • 创建文件夹没有权限会报错
  • os.MkdirAll创建文件夹 , 需要制定权限
    • 创建文件夹, 不存在就创建, 存在返回nil
  • os.Remove() 删除指定文件夹, 非空不能删除
  • os.RemoveAll() 删除指定文件夹, 非空也删除
  • os.OpenFile() 创建/读取文件
  • os.Open() 读文件
  • os.ModePerm 返回值: -rwxrwxrwx,类似0777
# os.Open 与读的方式

f ,e := os.OpenFile("data.csv")

# os.OpenFile 读写方式

f ,e := os.OpenFile("data.csv", os.O_CREATE|os.O_RDWR, 0644)

# FileInfo

FileInfo 接口中定义了 File 信息相关的方法。

type FileInfo interface {
    Name() string       // base name of the file 文件名.扩展名 aa.txt
    Size() int64        // 文件大小,字节数 12540
    Mode() FileMode     // 文件权限 -rw-rw-rw-
    ModTime() time.Time // 修改时间 2020-09-23 16:30:53 +0800 CST
    IsDir() bool        // 是否文件夹
    Sys() interface{}   // 基础数据源接口(can return nil)
}
1
2
3
4
5
6
7
8

# 权限

至于操作权限 perm,除非创建文件时才需要指定,不需要创建新文件时可以将其设定为0。虽然 Golang 语言给 perm 权限设定了很多的常量,但是习惯上也可以直接使用数字,如 0666 (具体含义和 Unix 系统的一致)。 权限控制:

linux 下有2种文件权限表示方式,即“符号表示”和“八进制表示”。

(1)符号表示方式:
-      ---         ---        ---
type   owner       group      others
文件的权限是这样子分配的 读 写 可执行 分别对应的是 r w x 如果没有那一个权限,用 - 代替
(-文件 d目录 |连接符号)
例如:-rwxr-xr-x

(2)八进制表示方式: 
r ——> 004
w ——> 002
x ——> 001
- ——> 000

0755
0777
0555
0444
0666
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 创建文件夹

  • os.MkDir("dirName",os.ModePerm ),创建一层
  • os.MkDirAll("dirName",os.ModePerm ),可以创建多层

# 创建文件

  • os.Create(),创建文件
    • 采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会替换它(为空文件)

# 打开/关闭文件

  • os.Open(fileName) 只读

  • os.OpenFile(filename,mode,perm) --文件名称|文件的打开方式|文件的权限

    file4,err := os.OpenFile(fileName1,os.O_RDONLY|os.O_WRONLY,os.ModePerm)
    
    1
    1. 第一个参数:文件名称

    2. 第二个参数:文件的打开方式

      模式 含义
      os.O_WRONLY 只写
      os.O_CREATE 创建文件
      os.O_RDONLY 只读
      os.O_RDWR 读写
      os.O_TRUNC 清空
      os.O_APPEND 追加
      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.
      
      ) 
      
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
    3. 第三个参数:文件的权限:文件不存在创建文件,需要指定权限

    package main
    
    import (
    	// "fmt"
    	"fmt"
    	"os"
    )
    
    func main() {
    	file, err := os.Open("word.txt") // 读取文件
    	if err != nil {
    		fmt.Println("error:", err)
    		return
    	}
    	defer file.Close()
    	fileinfo, err := file.Stat()
    	if err != nil {
    		fmt.Println(err)
    		return
    	}
    	fileSize := fileinfo.Size()   // 文件大小
    	buffer := make([]byte, fileSize)
    	bytesread, err := file.Read(buffer)  //获取文件内容
    	if err != nil {
    		fmt.Println("err::", err)
    	}
    	fmt.Println("bytes read: ", bytesread)
    	fmt.Println("bytestream to string: ", string(buffer))
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
  • file.Close() 关闭文件

# 创建/删除文件/目录

  • os.Create(),创建文件
    • 采用模式0666(任何人都可读写,不可执行)创建一个名为name的文件,如果文件已存在会替换它(为空文件)
  • 删除文件 os.Remove()
  • 删除文件夹 os.RemoveAll()
//删除文件
err :=  os.Remove("/Users/ruby/Documents/pro/a/aa.txt")
if err != nil{
  fmt.Println("err:",err)
  return
}
fmt.Println("删除文件成功。。")
//删除目录
err :=  os.RemoveAll("/Users/ruby/Documents/pro/a/cc")
if err != nil{
    fmt.Println("err:",err)
    return
}
fmt.Println("删除目录成功。。")
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 判断文件是否存在

Golang 判断文件或文件夹是否存在的方法为使用 os.Stat() 函数返回的错误值进行判断。

  1. 如果返回的错误为 nil,说明文件或文件夹存在
  2. 如果返回的错误类型使用 os.IsNotExist() 判断为 true,说明文件或文件夹不存在
package main
import (
    "log"
    "os"
)

func main() {
    fileInfo,err:=os.Stat("/Users/ruby/Documents/pro/a/aa.txt")
    if err!=nil{
        if os.IsNotExist(err){
            log.Fatalln("file does not exist")
        }
    }
    log.Println("file does exist. file information:")
    log.Println(fileInfo)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 读取文件内容

  • 读文件方式一:利用ioutil.ReadFile直接从文件读取到[]byte中
func Read0()  (string){
    f, err := ioutil.ReadFile("file/test")
    if err != nil {
        fmt.Println("read fail", err)
    }
    return string(f)
}
1
2
3
4
5
6
7
  • 读文件方式二:先从文件读取到file中,在从file读取到buf, buf在追加到最终的[]byte
func Read1()  (string){
    //获得一个file
    f, err := os.Open("file/test")
    if err != nil {
        fmt.Println("read fail")
        return ""
    }

    //把file读取到缓冲区中
    defer f.Close()
    var chunk []byte
    buf := make([]byte, 1024)

    for {
        //从file读取到buf中
        n, err := f.Read(buf)
        if err != nil && err != io.EOF{
            fmt.Println("read buf fail", err)
            return ""
        }
        //说明读取结束
        if n == 0 {
            break
        }
        //读取到最终的缓冲区中
        chunk = append(chunk, buf[:n]...)
    }

    return string(chunk)
    //fmt.Println(string(chunk))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  • 读文件方式三:先从文件读取到file, 在从file读取到Reader中,从Reader读取到buf, buf最终追加到[]byte
//先从文件读取到file, 在从file读取到Reader中,从Reader读取到buf, buf最终追加到[]byte,这个排第三
func Read2() (string) {
    fi, err := os.Open("file/test")
    if err != nil {
        panic(err)
    }
    defer fi.Close()

    r := bufio.NewReader(fi)
    var chunks []byte

    buf := make([]byte, 1024)

    for {
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if 0 == n {
            break
        }
        //fmt.Println(string(buf))
        chunks = append(chunks, buf...)
    }
    return string(chunks)
    //fmt.Println(string(chunks))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • 读文件方式四:读取到file中,再利用ioutil将file直接读取到[]byte中
//读取到file中,再利用ioutil将file直接读取到[]byte中, 这是最优
func Read3()  (string){
    f, err := os.Open("file/test")
    if err != nil {
        fmt.Println("read file fail", err)
        return ""
    }
    defer f.Close()

    fd, err := ioutil.ReadAll(f)
    if err != nil {
        fmt.Println("read to fd fail", err)
        return ""
    }

    return string(fd)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

四种方式读的速度排名是:前者为优 方式四 > 方式一 > 方式三 > 方式二

# 写文件内容

  • 写文件方式一:使用 io.WriteString 写入文件
func Write0()  {
    fileName := "file/test1"
    strTest := "测试测试"

    var f *os.File
    var err error

    if CheckFileExist(fileName) {  //文件存在
        f, err = os.OpenFile(fileName, os.O_APPEND, 0666) //打开文件
        if err != nil{
            fmt.Println("file open fail", err)
            return
        }
    }else {  //文件不存在
        f, err = os.Create(fileName) //创建文件
        if err != nil {
            fmt.Println("file create fail")
            return
        }
    }
    //将文件写进去
    n, err1 := io.WriteString(f, strTest)
    if err1 != nil {
        fmt.Println("write error", err1)
        return
    }
    fmt.Println("写入的字节数是:", n)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • 写文件方式二:使用 ioutil.WriteFile 写入文件
func Write1()  {
    fileName := "file/test2"
    strTest := "测试测试"
    var d = []byte(strTest)
    err := ioutil.WriteFile(fileName, d, 0666)
    if err != nil {
        fmt.Println("write fail")
    }
    fmt.Println("write success")
}
1
2
3
4
5
6
7
8
9
10
  • 写文件方式三:使用 File(Write,WriteString) 写入文件
func Write2()  {

    fileName := "file/test3"
    strTest := "测试测试"
    var d1 = []byte(strTest)

    f, err3 := os.Create(fileName) //创建文件
    if err3 != nil{
        fmt.Println("create file fail")
    }
    defer f.Close()
    n2, err3 := f.Write(d1) //写入文件(字节数组)

    fmt.Printf("写入 %d 个字节n", n2)
    n3, err3 := f.WriteString("writesn") //写入文件(字节数组)
    fmt.Printf("写入 %d 个字节n", n3)
    f.Sync()
}
// 或者
func WriteFile(fPath string) {
	//f, _ := os.OpenFile(fPath,os.O_APPEND,0666)
	f, err := os.OpenFile(fPath, os.O_CREATE|os.O_WRONLY, os.ModeAppend)
	defer f.Close()
	writeString, err := f.WriteString("你好")
	if err != nil {
		fmt.Println(writeString)
		panic(err)
		return
	}
	fmt.Println(writeString)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  • 写文件方式四:使用 bufio.NewWriter 写入文件
func Write3()  {
    fileName := "file/test3"
    f, err3 := os.Create(fileName) //创建文件
    if err3 != nil{
        fmt.Println("create file fail")
    }
    w := bufio.NewWriter(f) //创建新的 Writer 对象
    n4, err3 := w.WriteString("bufferedn")
    fmt.Printf("写入 %d 个字节n", n4)
    w.Flush()
    f.Close()
}
1
2
3
4
5
6
7
8
9
10
11
12

# JSON文件操作

# 编码JSON

  • 编码json: 从其他类型编码成json字符串

  • encoding/json

    • Marshal 返回interface{}类型 的json编码, 通常interface{}类型会使用map或者结构体
    • MarshalIndent 类似于Marshal, 会使用缩进输出格式化json
  • 使用map创建json

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    /**
    map创建json
     */
    func main() {
    	m:=make(map[string]interface{},3)
    	m["name"] = "evan"
    	m["age"] = 27
    	m["language"] = []string{"python","golang","javascript"}
    
    	result,_:=json.Marshal(m)
    	resultMarshalIndent,_:=json.MarshalIndent(m,"","    ")
    	fmt.Println(string(result))
    	fmt.Println(string(resultMarshalIndent))
    }
    
    /**
    {"age":27,"language":["python","golang","javascript"],"name":"evan"}
    {
        "age": 27,
        "language": [
            "python",
            "golang",
            "javascript"
        ],
        "name": "evan"
    }
    */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
  • 使用结构体创建json(常用)

    • 当在定义struct 的时, 可以在后面添加标签来控制编码和解码的过程; 是否要编码或者解码某个字段, JSON中的名字字段名称是什么, 可以选择的控制字段有三种
      1. "-" :表示不要解析该字段
      2. "omitempty" : 当字段为空的时候不要解析该字段, 比如: false 0 nil 长度为0的array map slice string
      3. "FieldName" : 当解析JSON的时候使用这个名字
    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name     string `json:"name"`
    	Age      int    `json:"age"`
    	Sex      bool   `json:"sex"`
    	Birthday string `json:"birthday"`
    	Company  string `json:"company,omitempty"`
    	Language []string `json:"language"`
    }
    
    func main() {
    	person :=Person{"Evan",28,true,"1994","DCITS",[]string{
    		"python","golang",
    	}}
    
    	//result,err :=json.Marshal(person)
    	result,err :=json.MarshalIndent(person,"","    ")
    	if err !=nil{
    		fmt.Println(err)
    		return
    
    	}
    	fmt.Println(string(result))
    
    }
    /**
    {
        "name": "Evan",
        "age": 28,
        "sex": true,
        "birthday": "1994",
        "company": "DCITS",
        "language": [
            "python",
            "golang"
        ]
    }
    */
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44

# 解析JSON

  • Unmarshal() 解析json,是Marshal()的反向操作

  • 要将json数据解码写入一个接口类型值, 函数会将解码数据为如下对照关系写入接口

    interface类型 json类型
    Bool 布尔类型
    Float64 数字类型
    string 字符串类型
    []interface{} 数组
    map 对象
    nil null
    • 如果json的值不满足或者不匹配给出的目标类型, 或者JSON数字写入目标类型时溢出, unmarsha()函数会跳过该字段, 尽可能满足其余的解码操作
  • struce 解码json(推荐使用)

    package main
    
    import (
    	"encoding/json"
    	"fmt"
    )
    
    type Person struct {
    	Name     string   `json:"name"`
    	Age      int      `json:"age"`
    	Sex      bool     `json:"sex"`
    	Birthday string   `json:"birthday"`
    	Company  string   `json:"company,omitempty"`
    	Language []string `json:"language"`
    }
    
    func main() {
    	jsonStr := `
    		{   "name":"evan",	
    			"age":28,
    			"sex":true,
    			"birthday":"1994",
    			"company":"DCITS",
    			"language":["python","golang","javascript"]
    		}
    		`
    	var person Person
    
    	err:=json.Unmarshal([]byte(jsonStr),&person)
    
    	if err!=nil {
    		fmt.Println(err)
    		return
    
    	}
    	fmt.Println(person)
    }
    // {evan 28 true 1994 DCITS [python golang javascript]}
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38

# 拓展 fastjson

  • 速度是原生json操作速度的10倍
  • 地址: https://github.com/valyala/fastjson

# XML文件操作

  • XML是一门标记语言

  • XML对大小写敏感

    • Xml 文件

      <?xml version="1.0" encoding="utf-8" ?>
      <Wrapper>
          <Note>
              <To>George</To>
              <From>John</From>
              <Body>
                  <Bodychild>bc1</Bodychild>
                  <Bodychild>bc2</Bodychild>
              </Body>
          </Note>
          <Note>
              <To>George2</To>
              <From>John2</From>
              <Body>
                  <Bodychild>bc1</Bodychild>
                  <Bodychild>bc2</Bodychild>
              </Body>
          </Note>
      </Wrapper>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
    • golang code

      package main
      
      import (
      	"encoding/xml"
      	"fmt"
      	"io/ioutil"
      )
      
      type Wrapper struct {
      	Note []Note
      }
      
      type Note struct{
      	To string
      	From string
      	Body Body
      }
      
      type Body struct {
      	Bodychild []string
      }
      
      func main() {
      	var res Wrapper
      	content,err:=ioutil.ReadFile("test.xml")
      
      	if err!=nil{
      		fmt.Println(err)
      		return
      
      	}
      	err = xml.Unmarshal(content,&res)
      	if err !=nil {
      		fmt.Println(err)
      		return
      	}
      	fmt.Println("解析后的xml文件为:")
      	fmt.Println(res)
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39

# 按行读文件

  • 方法一

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"io"
    	"os"
    )
    
    const FilePath = "./test.txt"
    
    func readLineOfOne() {
    	f, err := os.Open(FilePath)
    	if err!=nil {
    		fmt.Println(err)
    		os.Exit(2)
    	}
    	defer f.Close()
    	bufReader := bufio.NewReader(f)
    	i := 0
    	for {
    		i++
    		//fmt.Println(i)
    		line,err:= bufReader.ReadBytes('\n')
    		fmt.Println("->",string(line))
    		if err== io.EOF {
    			fmt.Println("read file finished.")
    			break
    		}else if err!= nil	{
    			fmt.Println(err)
    			os.Exit(2)
    		}
    
    	}
    
    }
    
    func main() {
    	readLineOfOne()
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    • bufReader.ReadBytes('\n')和 bufReader.ReadString('\n')在读到文件最后一行时,会同时返回内容line和io.EOF

# bufio.Reader

  • 方法一(一行一行读)
f, err := os.Open("./src/day1/file_read/1.txt")
    if err != nil{
        fmt.Println(err)
        os.Exit(2)
    }
    defer f.Close()
    bufReader := bufio.NewReader(f)
    var i = 0
    for{
        i++
        fmt.Println(i)
        line,err := bufReader.ReadBytes('\n')
        fmt.Println(string(line))
        if err == io.EOF {
            fmt.Println("read the file finished")
            break
        }
        if err != nil{
            fmt.Println(err)
            os.Exit(2)
        }

    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • 方法二
f, err := os.Open("./src/day1/file_read/1.txt")
    if err != nil{
        fmt.Println(err)
        os.Exit(2)
    }
    defer f.Close()
    bufReader := bufio.NewReader(f)
    var buf [256]byte
    var i = 0
    for{
                i++
        fmt.Println(i)
        n,err := bufReader.Read(buf[:])
        if err == io.EOF {
            fmt.Println("read the file finished")
            break
        }
        if err != nil{
            fmt.Println(err)
            os.Exit(2)
        }
        fmt.Println(string(buf[:n]))
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  • bufReader.ReadBytes('\n')和 bufReader.ReadString('\n')在读到文件最后一行时,会同时返回内容line和io.EOF。而bufReader.Read()读取到末尾时,会先返回内容,然后再下一次迭代时才返回io.EOF

# 读写文件的四种方式

# 读文件

读取的文件放在file/test:也就是file包下的test这个文件,里面写多一点文件

  • 读文件方式一:利用ioutil.ReadFile直接从文件读取到[]byte中

  • ioutil.ReadFile 将文件全部读到内存

func Read0()  (string){
    f, err := ioutil.ReadFile("file/test")
    if err != nil {
        fmt.Println("read fail", err)
    }
    return string(f)
}
1
2
3
4
5
6
7
  • 读文件方式二:先从文件读取到file中,在从file读取到buf, buf在追加到最终的[]byte

  • os.Open 文件流的方式读取文件

func Read1()  (string){
    //获得一个file
    f, err := os.Open("file/test")
    if err != nil {
        fmt.Println("read fail")
        return ""
    }

    //把file读取到缓冲区中
    defer f.Close()
    var chunk []byte
    buf := make([]byte, 1024)

    for {
        //从file读取到buf中
        n, err := f.Read(buf)
        if err != nil && err != io.EOF{
            fmt.Println("read buf fail", err)
            return ""
        }
        //说明读取结束
        if n == 0 {
            break
        }
        //读取到最终的缓冲区中
        chunk = append(chunk, buf[:n]...)
    }

    return string(chunk)
    //fmt.Println(string(chunk))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  • 读文件方式三:先从文件读取到file, 在从file读取到Reader中,从Reader读取到buf, buf最终追加到[]byte
//先从文件读取到file, 在从file读取到Reader中,从Reader读取到buf, buf最终追加到[]byte,这个排第三
func Read2() (string) {
    fi, err := os.Open("file/test")
    if err != nil {
        panic(err)
    }
    defer fi.Close()

    r := bufio.NewReader(fi)
    var chunks []byte

    buf := make([]byte, 1024)

    for {
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if 0 == n {
            break
        }
        //fmt.Println(string(buf))
        chunks = append(chunks, buf...)
    }
    return string(chunks)
    //fmt.Println(string(chunks))
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  • 读文件方式四:读取到file中,再利用ioutil将file直接读取到[]byte中
//读取到file中,再利用ioutil将file直接读取到[]byte中, 这是最优
func Read3()  (string){
    f, err := os.Open("file/test")
    if err != nil {
        fmt.Println("read file fail", err)
        return ""
    }
    defer f.Close()

    fd, err := ioutil.ReadAll(f)
    if err != nil {
        fmt.Println("read to fd fail", err)
        return ""
    }

    return string(fd)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • 读取速度比较

经过我的测试,这四种方式读的速度排名是:前者为优 方式四 > 方式一 > 方式三 > 方式二

# 写文件

  • 写文件方式一:使用 io.WriteString 写入文件
func Write0()  {
    fileName := "file/test1"
    strTest := "测试测试"

    var f *os.File
    var err error

    if CheckFileExist(fileName) {  //文件存在
        f, err = os.OpenFile(fileName, os.O_APPEND, 0666) //打开文件
        if err != nil{
            fmt.Println("file open fail", err)
            return
        }
    }else {  //文件不存在
        f, err = os.Create(fileName) //创建文件
        if err != nil {
            fmt.Println("file create fail")
            return
        }
    }
    //将文件写进去
    n, err1 := io.WriteString(f, strTest)
    if err1 != nil {
        fmt.Println("write error", err1)
        return
    }
    fmt.Println("写入的字节数是:", n)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • 写文件方式二:使用 ioutil.WriteFile 写入文件
func Write1()  {
    fileName := "file/test2"
    strTest := "测试测试"
    var d = []byte(strTest)
    err := ioutil.WriteFile(fileName, d, 0666)
    if err != nil {
        fmt.Println("write fail")
    }
    fmt.Println("write success")
}
1
2
3
4
5
6
7
8
9
10
  • 写文件方式三:使用 File(Write,WriteString) 写入文件
func Write2()  {

    fileName := "file/test3"
    strTest := "测试测试"
    var d1 = []byte(strTest)

    f, err3 := os.Create(fileName) //创建文件
    if err3 != nil{
        fmt.Println("create file fail")
    }
    defer f.Close()
    n2, err3 := f.Write(d1) //写入文件(字节数组)

    fmt.Printf("写入 %d 个字节n", n2)
    n3, err3 := f.WriteString("writesn") //写入文件(字节数组)
    fmt.Printf("写入 %d 个字节n", n3)
    f.Sync()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 写文件方式四:使用 bufio.NewWriter 写入文件
func Write3()  {
    fileName := "file/test3"
    f, err3 := os.Create(fileName) //创建文件
    if err3 != nil{
        fmt.Println("create file fail")
    }
    w := bufio.NewWriter(f) //创建新的 Writer 对象
    n4, err3 := w.WriteString("bufferedn")
    fmt.Printf("写入 %d 个字节n", n4)
    w.Flush()
    f.Close()
}
1
2
3
4
5
6
7
8
9
10
11
12
  • 检查文件是否存在:
func CheckFileExist(fileName string) bool {
    _, err := os.Stat(fileName)
    if os.IsNotExist(err) {
        return false
    }
    return true
}
1
2
3
4
5
6
7
#Go#
上次更新: 2023/04/16, 18:35:33
空结构体
并发与通道

← 空结构体 并发与通道→

最近更新
01
go与http代理
05-24
02
自制申威架构k8s-reloader
12-06
03
Docker Buildx 教程
12-01
更多文章>
Theme by Vdoing | Copyright © 2020-2024 小刘扎扎 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式