go语言读取文件

file 是一个地址,指向文件的句柄

file 是一个地址,指向文件的句柄

err 等于 nil 表示打开文件成功

复制代码
package main

import (
	"fmt"
	"os"
)
func main() {
	// 只读的方式打开文件
	// file 是一个地址,指向文件的句柄
  // err 等于 nil 表示打开文件成功
  // err 不等于 nil 表示打开文件失败
	file, err := os.Open("./45.md")
	if err != nil {
		fmt.Println(err)
		return
	}
  // 打开文件之后,你一定要记得关闭文件哈;否则会造成内存泄漏
	defer file.Close()
	fmt.Println(file)
}

输出:&{0xfa0de47c240}

读取某个文件

复制代码
package main

import (
	"fmt"
	"os"
)

func main() {
	// 只读的方式打开文件
	// file 是一个地址,指向文件的句柄
	file, err := os.Open("./45.md")
	if err != nil {
		fmt.Println(err)
		return
	}
  // 打开文件之后,你一定要记得关闭文件哈;否则会造成内存泄漏
	defer file.Close()
	fmt.Println(file)
	// 创建一个byte类型的切片
	var tempSlice = make([]byte, 128)
	// 从文件中读取数据;每次只能读取128字节;因为tempSlice是一个字节数组,大小为128,所以只能读取128字节
	// file.read(tempSlice) 的参数是一个byte类型的切片,返回值是一个读取到字节数的整数,以及一个错误值
	n, err := file.Read(tempSlice)
	if err != nil {
		fmt.Println("读取文件失败")
		fmt.Println(err)
		return
	}
	fmt.Printf("%d 字节", n)
	fmt.Printf("读取到的内容", string(tempSlice))
}

读取文件的全部内容,出现问题

我们发现读取到的内容是不全的哈;

这是因为我们每次只能读取128字节,而文件的大小可能大于128字节。

所以,我们需要使用一个循环,每次读取128字节,直到读取到文件的末尾。

读取文件的全部内容

复制代码
package main

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

func main() {
	// 只读的方式打开文件
	// file 是一个地址,指向文件的句柄
	file, err := os.Open("./45.md")
	if err != nil {
		fmt.Println(err)
		return
	}
	// 打开文件之后,你一定要记得关闭文件哈;否则会造成内存泄漏
	defer file.Close()
	fmt.Println(file)

	var strSlice []byte
	// 创建一个byte类型的切片;每次都会读取128字节。如果不足128字节,那么就会出现问题
	var tempSlice = make([]byte, 128)
	for {
		n, err := file.Read(tempSlice)
		// 读取到文件末尾,err返回io.EOF
		if err == io.EOF {
			fmt.Println("读取完成")
			break
		}
		if err != nil {
			fmt.Println("读取文件失败")
			return
		}
		// 把每次读取到的内容,追加到strSlice中(只取实际读到的n个字节)
		strSlice = append(strSlice, tempSlice[:n]...)
	}
	fmt.Println("读取到的内容:", string(strSlice))
}

现在我们就可以把文件的全部内容给读取出来。

容易出现的其他问题:

最后一次读取通常不足 128 字节,tempSlice里会残留上一轮的数据。

所以必须用[:n] 截取有效部分,不能用整个tempSlice

复制代码
n, err := file.Read(tempSlice)
// ...
strSlice = append(strSlice, tempSlice[:n]...)

一次读取一行文件的内容

复制代码
package main
import (
	"bufio"
	"fmt"
	"os"
)
func main() {
	// file 是一个地址,指向文件的句柄
	file, err := os.Open("./45.md")
	if err != nil {
		fmt.Println(err)
		return
	}
	// 打开文件之后,你一定要记得关闭文件哈;否则会造成内存泄漏
	defer file.Close()
	// 创建一个bufio.Reader类型的变量,指向读取文件的内容
	reader := bufio.NewReader(file)
	// 每次读取一行内容
	str, err := reader.ReadString('\n')
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(str)
}

for循环读取文件的全部内容:一次读取一行文件的内容

复制代码
package main

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

func main() {

	// file 是一个地址,指向文件的句柄
	file, err := os.Open("./45.md")
	if err != nil {
		fmt.Println(err)
		return
	}
	// 打开文件之后,你一定要记得关闭文件哈;否则会造成内存泄漏
	defer file.Close()
	// 定义一个字符串,用来存储文件的内容
	var fileStr string
	// 创建一个bufio.Reader类型的变量,指向读取文件的内容
	reader := bufio.NewReader(file)
	for {
		// 每次读取一行内容
		str, err := reader.ReadString('\n')
		// 如果读取到文件的末尾,就跳出循环
		if err == io.EOF {
			// 否则会出现文件文件读取不完的情况(文件中间出现空白行)
			fileStr += str
			break
		}
		if err != nil {
			fmt.Println(err)
			return
		}
		fileStr += str
	}
	fmt.Println(fileStr)
}

文件较小的话,可以通过这样的方式一次性全部读取出来

复制代码
package main
import (
	"fmt"
	"io/ioutil"
)
func main() {
	byteStr, err := ioutil.ReadFile("./45.md")
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(byteStr))
}

name 表示你要打开的文件名

flag 表示你要打开的文件模式,有下面这几种模式

OS.O_WRONLY:只写

Os.O_CREATE:创建文件

Os.O_RDONLY:只读

OS.O_RDWR:读写

Os.O_TRUNC:清空

OS.O_APPEND:追加

perm 表示文件权限

perm:文件权限,一个八进制数。r(读)04,w(写)02,×(执行)01。

给文件写入数据

复制代码
package main

import (
	"fmt"
	"os"
)

func main() {
	// 打开文件
	// name 表示你要打开的文件名
	// flag 表示你要打开的文件模式
	// - `os.O_CREATE` :文件不存在就创建
	// - `os.O_WRONLY` :只写模式
	// - `os.O_TRUNC` :打开时清空原有内容
	// 权限`0666` 是八进制读写权限(在 Windows 下基本不起作用,主要对 Linux 有效)
	file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()
	file.WriteString("hello world")
}

现在这样,就可以给文件中写入数据了。

通过循环给文件写入数据

复制代码
package main

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

func main() {
	// 打开文件
	// name 表示你要打开的文件名
	// flag 表示你要打开的文件模式
	// - `os.O_CREATE` :文件不存在就创建
	// - `os.O_WRONLY` :只写模式
	// - `os.O_TRUNC` :打开时清空原有内容
	// 权限`0666` 是八进制读写权限(在 Windows 下基本不起作用,主要对 Linux 有效)
	file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()
	for i := 0; i < 10; i++ {
		// strconv.Itoa(i) 将整数转换为字符串
		// "\n" 表示换行
		file.WriteString("hello world " + strconv.Itoa(i) + "\n")
	}
}

通过file.Write(\[\]byte(str))来写入文件

复制代码
package main

import (
	"fmt"
	"os"
)

func main() {
	// 打开文件
	// name 表示你要打开的文件名
	// flag 表示你要打开的文件模式
	// - `os.O_CREATE` :文件不存在就创建
	// - `os.O_WRONLY` :只写模式
	// - `os.O_TRUNC` :打开时清空原有内容
	// 权限`0666` 是八进制读写权限(在 Windows 下基本不起作用,主要对 Linux 有效)
	file, err := os.OpenFile("testFile.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()

	var str = "直接写入数据"
	// 写入数据
	// []byte(str) 将字符串转换为字节数组
	file.Write([]byte(str))
}

bufio.NewWriter(file)来写入文件

复制代码
package main

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

func main() {
	// 打开文件
	// name 表示你要打开的文件名
	// flag 表示你要打开的文件模式
	// - `os.O_CREATE` :文件不存在就创建
	// - `os.O_WRONLY` :只写模式
	// - `os.O_TRUNC` :打开时清空原有内容
  // - `os.O_APPEND` :追加模式
	// 权限`0666` 是八进制读写权限(在 Windows 下基本不起作用,主要对 Linux 有效)
	file, err := os.OpenFile("testFile.txt", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer file.Close()
	writer := bufio.NewWriter(file)
	// 表示写入到缓存中去
	writer.WriteString("hello golang")
	// 表示将缓存中的数据写入到文件中
	writer.Flush()
}

ioutil.WriteFile 来写入文件

复制代码
package main

import (
	"fmt"
	"io/ioutil"
)

func main() {
	str := "hello golang"
	// 写入文件,会覆盖原有内容
	// []byte(str) 将字符串转换为字节数组
	err := ioutil.WriteFile("testFile.txt", []byte(str), 0666)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("写入成功")
}