文件操作、终端输入、文件存储~ 够浪|Go主题月

492 阅读4分钟

上图

创建文件

package main

import (
	"fmt"
	"os"
)

func main() {
	file, err := os.Create(`E:\Code\moose-workspace\go-lean\input_output\demo.txt`)

	if err != nil {
		fmt.Println("文件创建失败")
        fmt.Println(err)
		return
	}

	defer file.Close()
}
  • 在 golang 中,创建文件,使用 os 包

  • os.Create(name string) 创建文件,指定存储文件磁盘路径

    • 指定相对路径:比如 "./demo.txt" 会在当前项目根路径下创建文件,指定磁盘路径会在自定位置创建

    • 如果磁盘路径不存在,创建文件会失败,报错

      因为 E:\Code\moose-workspace\go-lean\input 这个目录是没有的

      open E:\Code\moose-workspace\go-lean\input\demo.txt: The system cannot find the path specified.

  • defer 推迟的意思吧,关键字 file.Close() 文件读写完,把文件流关闭,避免资源浪费

  • 运行之后,会在指定的位置看到这个文件 ~

创建目录

path := `E:\Code\moose-workspace\go-lean\input`

if _, err := os.Stat(path); os.IsNotExist(err) {
    os.Mkdir(path, os.ModePerm)
}
  • 在文件目录不存在则创建文件目录
  • os.Stat 判断文件是否存在
  • os.IsNotExist(err) Stat 文件不存在,会抛出一个异常,判断异常
  • os.Mkdir 创建目录,指定访问权限
  • 这个时候再去写文件都是OK的

查看返回值

在学习的时候,通常不知道返回什么类型,可以点击对应的方法去看源码

  • 发现这个返回一个文件对象和一个错误对象

  • File 表示打开的文件描述符。

  • error 是 go 中内建错误

从 os.Create() 学到

  • go 中的函数返回值,可以返回多个参数,返回的参数需要和返回值类型对应上
  • 查看了源码之后,发现 go lang 中很多返回都是这样返回的

定义一个函数

func GetUserInfo(userid int) (name string, avatar string, age int) {
	if userid == 10001 {
		return "测试用户", "https://gitee.com/shizidada/moose-resource/raw/master/default-avatar.png", 10
	}
	return "", "", 0
}
  • 这个方法是模拟根据用户 id 获取用户信息,返回多个值
  • 只有 userid 匹配时才会返回

调用

...
	name, avatar, age := GetUserInfo(10001)
	fmt.Printf("姓名 %s 头像 %s 年龄 %d", name, avatar, age)
...

  • 没有匹配会返回空

os.Open os.Create 区别

  • Open 打开文件,只有只读权限 O_RDONLY
  • Create 创建文件,读写,创建,清空权限 O_RDWR|O_CREATE|O_TRUNC

写文件

Create 的时候,返回了file 文件标识符,可以用这个去写文件了

file.WriteString("哈哈哈,写入文字")
file.Write([]byte("哈哈哈,byte 写入"))

读文件

...

fileinfo, err := os.Stat(filename)
filesize := fileinfo.Size()

file, err = os.Open(filename)

buf := make([]byte, filesize)
count := 0
for {
    count, err = file.Read(buf)
    if err == io.EOF {
        fmt.Println("end ...")
        break
    }
    fmt.Print(string(buf[:count]))
}
...

  • for 循环读取文件
  • file.Read 需要传递一个缓冲区
  • 通过 os.Stat 可以获取文件的大小,构建一个缓冲区 buf
  • 读完文件,会抛出一个 EOF 错误,需要手动判断这个错误
  • string(buf[:count] 将 byte 转化为字符串

结合终端输入操作文件

package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

// 用常量来表示,不变的量
// 目录文件夹磁盘路径
const (
	FOLDERPATH = `E:\Code\moose-workspace\go-lean\input_output2`
)

func BuildNote() {

	// 输出提示
	fmt.Println("请输入文件")

	// bufio 创建 NewScanner
	// os.Stdin 标准输入
	input := bufio.NewScanner(os.Stdin)

	// 等待输入
	input.Scan()

	// 获取控制台输入文本内容
	filename := input.Text()

	// 字符串判断,以 .txt 结尾
	if !strings.HasSuffix(filename, ".txt") {
		fmt.Println("文件名输入不正确")
		return
	}

	// 拼接文件名字路径
	filename = fmt.Sprintf(`%s\%s`, FOLDERPATH, filename)

	// 使用 os.Create 创建文件
	file, err := os.Create(filename)
	if err != nil {
		fmt.Println("文件创建失败")
		return
	}

	// defer 推迟关闭文件流
	defer file.Close()

	// 控制台输入
	fmt.Println("输入标题")
	input = bufio.NewScanner(os.Stdin)
	input.Scan()

	// title 拼接一个换行符
	title := fmt.Sprintf("%s\n", input.Text())

	// 具体输出内容
	fmt.Println("请输入内容")
	input = bufio.NewScanner(os.Stdin)

	// 用来保存输入的内容
	contents := make(map[string]int)

	// for 循环,使控制台在按回车键之后不中断
	for {
		input.Scan()
		content := input.Text()
		content += "\n"

		// 判断输入内容是否为 exit,退出控制台输入
		if strings.Contains(content, "exit") {
			break
		}

		// 输入的内容,追加到 contents 中
		contents[content]++
	}

	// bufio 创建 NewWriter,用于写文件
	w := bufio.NewWriter(file)
	w.WriteString(title)

	// 遍历 contents,拿到出入的内容
	for line := range contents {

		// 写入
		w.WriteString(line)
	}

	// 刷新缓冲,写到文件中
	w.Flush()
}

func main() {

	// 构建函数
	BuildNote()

}

知识点

  • 使用 bufio 封装了文件 I\O,方便操作

  • fmt.XXX fmt 常用包,输出

  • make(map[string]int) 开辟一个切片

  • for line := range contents;range 遍历切片

  • w.WriteString 之后需要 w.Flush,不调用 文件不会写入到文件中

  • strings.XXX,调用 strings 包中封装判断字符串函数,还有很多,参考

不足之处还望提出,评论。

上一篇 Gin 框架在实践中学习 ~ 够浪|Go主题月