(八)文件的操作

1 读取文件

读文件用 os 包,需要注意的是在打开一个文件进行操作后需要及时关闭文件。用几个小例子来说明一下。

1.1 exa1

package main

import (
	"fmt"
	"os"
)

func main()  {

	// 打开一个文件
	// 概念说明:file的叫法
	// 1.file 叫 file对象
	// 2.file 叫 file指针
	// 3.file 叫 file文件句柄
	file, err := os.Open("d:/test.txt")
	if err != nil {
		fmt.Println("Open file err=", err)
	}

	// 输出以下内容可以看出file就是一个指针
	fmt.Printf("file=%v", file)  // 输出file=&{0xc000084780}

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

}

1.2 exa2

读文件的内容并显示在终端(带缓冲区的方式)使用os.Open(), file.close(), bufio.NewReader(), reader.ReadString函数和方法。

package main

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

func main()  {

	// 打开文件
	file, err := os.Open("d:/test.txt")

	if err != nil {
		fmt.Println("Open file err=", err)
	}

	// 当函数退出时候,要及时关闭文件句柄,否则会有内存泄漏
	defer file.Close()

	// 创建一个带缓冲的 *Reader
	// 默认缓冲区 4096
	reader := bufio.NewReader(file)
	for {
		str, err := reader.ReadString('\n')  // 每读到一个换行就结束一次
		if err == io.EOF {  // io.EOF代表文件的末尾
			break
		}
		// 输出内容
		fmt.Print(str)
	}

	fmt.Println("文件读取结束")
}
// 需要注意的是如果使用 if err == io.EOF ,那么在我们要读取的文件中最后一行一定是一个换行
// 否则不能读取到最后一行

1.3 exa3

读取文件的内容并显示在终端(使用ioutil一次将整个文件读入到内存中)这种方式适用于文件不大的情况,相关方法和函数(ioutil.ReadFile),此函数封装了打开和关闭的操作

package main

import (
	"fmt"
	"io/ioutil"
)

func main() {

	// 使用 ioutil.ReadFile 一次性将文件读取到位
	file := "d:/test.txt"
	content, err := ioutil.ReadFile(file)
	if err != nil {
		fmt.Printf("read file err = %v", err)
	}

	// 把读取到的内容显示到终端
	fmt.Printf("%v", content)  // []byte 会以byte切片的样式输出
	// 因为没有显式Open,因此也不需要显式的Close文件文件的Open和Close功能都被封装到函数中

	fmt.Printf("%s", content)  // 可以完整将字符串输出
	//fmt.Printf("%v", string(content))
}

1.4 判断文件是否存在

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

package main

import (
	"fmt"
	"os"
)

// 判断文件是否存在
func PathExists(path string) (bool, error) {

	_, err := os.Stat(path)
	if err == nil {  // 如果err为空,则证明文件存在
		return true, nil
	}


	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err

}

func main() {

	filePath := "d:/test.txt"

	b, err := PathExists(filePath)
	if b == true && err == nil {
		fmt.Printf("%v文件存在", filePath)
		return
	}
	fmt.Printf("%v文件不存在", filePath)

}

2 写入文件内容

需要用到 os.OpenFile 函数
func OpenFile(name string, flag int, perm FileMode) (file *File, err error)
说明: os.OpenFile 它会使用指定的选项(如os.o_RDONLY等)、指定的模式(如0666等,此选项只在linux系统中生效),如果成功,则返回的对象可以用于 I/O 操作

2.1 exa1

创建一个新文件,写入内容 5 句 “hello, Gardon”

package main

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

func main() {

	// 创建一个新文件,写入内容 5 句 "hello, Gardon"
	// 1.打开文件 d:/abc.txt
	filePath := "d:/abc.txt"
	file, err := os.OpenFile(filePath, os.O_CREATE | os.O_WRONLY, 0666)
	if err != nil {
		fmt.Printf("open file err = %v", err)
		return
	}

	// 准备写入5句话
	str := "hello, Gardon\r\n" // 表示换行
	writer := bufio.NewWriter(file)
	for i := 0; i < 5; i++ {
		writer.WriteString(str)
	}

	// 及时关闭file句柄
	defer file.Close()

	// 因为writer是带缓存,因此在调用WriteString方法时
	// 其实内容是先写入到缓存的,所以需要调用Flush方法,将缓冲的数据真正写入到文件中,
	// 否则文件中会没有数据
	writer.Flush()
}

2.2 exa2

打开一个已经存在的文件,将原来的内容覆盖成新的内容10句 “你好,我是老大”

package main

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

func main() {

	// 打开一个已经存在的文件,将原来的内容覆盖成新的内容10句 "你好,我是老大"
	// 1.打开文件 d:/abc.txt
	filePath := "d:/abc.txt"
	file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_TRUNC , 0666)
	if err != nil {
		fmt.Printf("open file err = %v", err)
		return
	}

	// 及时关闭file句柄
	defer file.Close()

	// 写入10句 "你好,我是老大"
	str := "你好,我是老大\r\n" // 表示换行
	writer := bufio.NewWriter(file)
	for i := 0; i < 10; i++ {
		writer.WriteString(str)
	}

	writer.Flush()
}

2.3 exa3

打开一个存在的文件,在原来的内容追加内容 'ABC!ENGHSK’

package main

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

func main() {

	// (3)打开一个存在的文件,在原来的内容追加内容 'ABC!ENGHSK'
	filePath := "d:/abc.txt"
	file, err := os.OpenFile(filePath, os.O_WRONLY | os.O_APPEND , 0666)
	if err != nil {
		fmt.Printf("open file err = %v", err)
		return
	}

	// 及时关闭file句柄
	defer file.Close()

	// 写入10句 'ABC!ENGHSK'
	str := "'ABC!ENGHSK'\r\n" // 表示换行
	writer := bufio.NewWriter(file)
	for i := 0; i < 10; i++ {
		writer.WriteString(str)
	}

	writer.Flush()
}

2.4 exa4

打开一个存在的文件,将原来的内容读出显示在终端,并且追加5句"hello, 北京"

package main

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

func main() {

	// (4)打开一个存在的文件,将原来的内容读出显示在终端,并且追加5句"hello, 北京"
	filePath := "d:/abc.txt"
	file, err := os.OpenFile(filePath, os.O_RDONLY | os.O_APPEND , 0666)
	if err != nil {
		fmt.Printf("open file err = %v", err)
		return
	}

	// 及时关闭file句柄
	defer file.Close()

	// 先读取原来的内容
	reader := bufio.NewReader(file)
	for {
		str, err := reader.ReadString('\n')
		if err == io.EOF {
			break
		}
		// 显示到终端
		fmt.Print(str)
	}

	// 写入10句 "hello, 北京"
	str := "hello, 北京\r\n" // 表示换行
	writer := bufio.NewWriter(file)
	for i := 0; i < 5; i++ {
		writer.WriteString(str)
	}

	writer.Flush()
}

2.5 exa5

编写一个程序,将一个文件的内容写入到另一个文件。这两个文件已经存在

package main

// 编写一个程序,将一个文件的内容写入到另一个文件。这两个文件已经存在
// 使用ioutil.ReadFile / ioutil.WriteFile

import (
	"fmt"
	"io/ioutil"
)

func main() {

	// 将d:/abc.txt文件内容导入到 f:/kkk.txt
	// 声明两个文件名
	file1Path := "d:/abc.txt"
	file2Path := "f:/kkk.txt"

	// 1.将d:/abc.txt内容读取到内存
	content, err := ioutil.ReadFile(file1Path)
	if err != nil {
		// 说明文件读取有错误
		fmt.Printf("read file err = %v\n", err)
		return
	}

	// 2.将读取到的内容写入到 f:/kkk.txt
	err = ioutil.WriteFile(file2Path, content, 0666)
	if err != nil {
		fmt.Printf("write file error = %v\n", err)
	}

}

3 文件的拷贝

3.1 拷贝非文本文件的文件

package main

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

// 将一张图片/电影/mp3文件拷贝到另一个文件中 需要用到io包(注意不是文本文件)
// io.Copy

// 编写一个函数,接收两个文件路径 srcFileName dstFileName
func CopyFile(dstFileName string, srcFileName string) (written int64, err error) {
	srcfile, err := os.Open(srcFileName)
	if err != nil {
		fmt.Printf("Open file err = %v", err)
	}
	defer srcfile.Close()

	//通过srcfile句柄获取到 Reader
	reader := bufio.NewReader(srcfile)

	// 打开dstFileName(由于这个文件可能不存在,所以不能用os.Open来打开)
	dstFile, err := os.OpenFile(dstFileName, os.O_CREATE | os.O_WRONLY, 0666)
	if err != nil {
		fmt.Printf("open file err = %v", err)
		return
	}

	// 通过dstFile,获取到writer
	writer := bufio.NewWriter(dstFile)
	defer dstFile.Close()

	return io.Copy(writer, reader)
}

func main() {

	// 将 d:/flower.jpg 拷贝到 f:/abc.jpg

	// 调用CopyFile完成文件的拷贝
	srcFile := "d:/flower.jpg"
	dstFile := "f:/abc.jpg"

	_, err := CopyFile(dstFile, srcFile)
	if err == nil {
		fmt.Println("Copy Successd!")
	} else {
		fmt.Println("Copy error info = %v", err)
	}
}

3.2 拷贝文本文件

package main

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

// 将文本文件拷贝到另一个文件中 需要用到io包,
// io.Copy

// 编写一个函数,接收两个文件路径 srcFileName dstFileName
func CopyFile(dstFileName string, srcFileName string) (written int64, err error) {
	srcfile, err := os.Open(srcFileName)
	if err != nil {
		fmt.Printf("Open file err = %v", err)
	}
	defer srcfile.Close()

	//通过srcfile句柄获取到 Reader
	reader := bufio.NewReader(srcfile)


	// 打开dstFileName(由于这个文件可能不存在,所以不能用os.Open来打开)
	dstFile, err := os.OpenFile(dstFileName, os.O_CREATE | os.O_WRONLY, 0666)
	if err != nil {
		fmt.Printf("open file err = %v", err)
		return
	}

	// 通过dstFile,获取到writer
	writer := bufio.NewWriter(dstFile)

	// 循环把src读取的每行数据写入到writer
	for {
		str, err := reader.ReadString('\n')
		if err == io.EOF {  // io.EOF代表文件的末尾
			break
		}
		// 显示到终端
		writer.WriteString(str)
	}

	// flush把缓冲的数据写入到真实文件中
	writer.Flush()
	defer dstFile.Close()

	return io.Copy(writer, reader)
}

func main() {

	// 将 d:/flower.txt 拷贝到 f:/abc.txt

	srcFile := "d:/flower.txt"
	dstFile := "f:/abc.txt"

	_, err := CopyFile(dstFile, srcFile)
	if err == nil {
		fmt.Println("Copy Successd!")
	} else {
		fmt.Println("Copy error info = %v", err)
	}
}

4 命令行参数

如果希望获取到命令行输入的各种参数,可以使用os.Args,它是一个string切片,用来存储所有的命令行参数

4.1 exa1

package main

import (
	"fmt"
	"os"
)

func main() {

	fmt.Println("命令行的参数有", len(os.Args))
	for i, v := range os.Args {
		fmt.Printf("args[%v]=%v\n", i, v)
	}

	/*
	D:\goproject\src\go_code\file\commandLineArgs>main.exe D:\goproject\src\go_code 99
	命令行的参数有 3
	args[0]=main.exe
	args[1]=D:\goproject\src\go_code
	args[2]=99
	*/
}

4.2 exa2 (flag)

golang中可以用flag包来解析命令行参数,exa1中使用的 os.Args 来获取命令行参数比较原生,解析不是特别方便,尤其是带有指定参数形式的命令行

package main

import (
	"fmt"
	"flag"
)

func main() {

	// 定义几个变量,用于接收命令行输入的参数值
	var user string
	var pwd string
	var host string
	var port int

	// &user 就是用来接收用户命令行中输入的 -u 后面的参数值
	// "u" 就是 -u 指定参数
	// "" 默认值
	// "用户名,默认为空" 对此参数的说明
	flag.StringVar(&user, "u", "", "用户名,默认为空")
	flag.StringVar(&pwd, "pwd", "", "密码,默认为空")
	flag.StringVar(&host, "h", "localhost", "主机名,默认为localhost")
	flag.IntVar(&port, "port", 3306, "端口,默认为3306")

	// 这里有一个非常重要的操作,转换  必须调用该方法
	flag.Parse()

	// 输出结果
	fmt.Printf("user=%v pwd=%v host=%v port=%v",
		user, pwd, host, port)
	/*
	可以不用指定顺序
	D:\goproject\src\go_code\file\commandLineArgs\flag>go build -o flag.exe main.go
	D:\goproject\src\go_code\file\commandLineArgs\flag>flag.exe -u root -pwd 12335465 -h 192.168.0.1 -port 8080
	user=root pwd=12335465 host=192.168.0.1 port=8080

	默认值
	D:\goproject\src\go_code\file\commandLineArgs\flag>flag.exe -u root -pwd 12335465
	user=root pwd=12335465 host=localhost port=3306

	*/
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RSQ博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值