【GO语言卵细胞级别教程】12.Go 语言文件操作秘籍:高效技巧解锁!

目录

【GO语言卵细胞级别教程】12.Go 语言文件操作秘籍:高效技巧解锁!1.文件模块简介1.1概述1.2打开文件1.3实战案例

2.io流操作文件2.1io流简介2.2IO流操作文件实战2.3其他的用途:

3.文件写入综合实践4.文件复制5.os包和bufio包操作文件的区别5.1概述5.2代码演示5.3特点和用法5.4问题

殺微信公众号:【给点知识】分享小知识,快速成长,欢迎关注呀!(底部点击二维码) 殺本项目演示代码仓库:https://gitee.com/gdzsfun/csdn-study-go 演示项目仓库 殺本项目创建方式:【GO语言卵细胞级别教程】05.项目创建和函数讲解 殺学习宗旨:活到老,学到老。 写作宗旨:致力于改变现有文章难读难懂问题。 今日分享诗句: ########### 蓬门未识绮罗香, 拟托良媒益自伤。 谁爱风流高格调, 共怜时世俭梳妆。 敢将十指夸针巧, 不把双眉斗画长。 苦恨年年压金线, 为他人作嫁衣裳。

1.文件模块简介

1.1概述

文件操作GO语言提供了os模块和io流

1.2打开文件

Go语言提供了丰富的文件操作功能,下面是一些常见的文件操作:

打开文件: 使用os.Open函数打开文件,它返回一个*os.File对象和一个可能的错误。可以指定打开文件的模式(只读、只写、追加等)。 file, err := os.Open("filename.txt")

if err != nil {

// 处理错误

}

defer file.Close() // 确保在函数结束时关闭文件

创建文件: 使用os.Create函数创建文件,如果文件已存在则截断文件内容。它返回一个*os.File对象和一个可能的错误。 file, err := os.Create("filename.txt")

if err != nil {

// 处理错误

}

defer file.Close() // 确保在函数结束时关闭文件

读取文件内容: 使用file.Read或file.ReadAt方法从文件中读取数据。Read方法将数据读取到指定的字节切片中,ReadAt方法从指定的偏移量开始读取数据。它们返回读取的字节数和可能的错误。 buffer := make([]byte, 1024)

numBytes, err := file.Read(buffer)

if err != nil {

// 处理错误

}

写入文件内容: 使用file.Write或file.WriteAt方法向文件中写入数据。Write方法从当前位置开始写入数据,WriteAt方法从指定的偏移量开始写入数据。它们返回写入的字节数和可能的错误。 data := []byte("Hello, World!")

numBytes, err := file.Write(data)

if err != nil {

// 处理错误

}

重命名文件: 使用os.Rename函数将文件重命名为新的名称。 err := os.Rename("oldname.txt", "newname.txt")

if err != nil {

// 处理错误

}

删除文件: 使用os.Remove函数删除文件。 err := os.Remove("filename.txt")

if err != nil {

// 处理错误

}

获取文件信息: 使用os.Stat函数获取文件的详细信息,包括文件名、大小、修改时间等。 fileInfo, err := os.Stat("filename.txt")

if err != nil {

// 处理错误

}

fmt.Println("文件名:", fileInfo.Name())

fmt.Println("文件大小:", fileInfo.Size())

fmt.Println("修改时间:", fileInfo.ModTime())

这只是一些常见的文件操作示例,Go语言的os和io包提供了更多功能丰富的文件操作函数。

1.3实战案例

获取文件基本信息和内容,具体步骤入下:

首先使用os.Open打开文件获取句柄使用句柄获取文件的基本信息,名称、路径等使用句柄获取文件的属性信息:调用Stat()方法获取属性结构体使用属性结构体获取文件的具体属性:大小、权限等 package mystudy

import (

"fmt"

"os"

"path" // path只能处理一种路径\\

"path/filepath" // filepath 可以处理相对复杂的分隔符 提供了相对路径和绝对路径的处理方法

)

func DemoFile01() {

fmt.Println("------文件操作------")

file, err := os.Open("D:/07.go/02.gostudy/goproject/src/com/gdzs/main/main.go")

if err != nil {

fmt.Println("Error:", err)

return

}

defer file.Close()

fmt.Println("文件绝对路径:", file.Name())

fmt.Println("文件名:", path.Base("D:/07.go/02.gostudy/goproject/src/com/gdzs/main/main"))

fmt.Println("文件名称:", filepath.Base("D:\\07.go\\02.gostudy\\goproject\\src\\com\\gdzs\\main\\main.go"))

fmt.Println(os.UserHomeDir())

fileInfo, err := file.Stat()

if err != nil {

fmt.Println("Error:", err)

return

}

fmt.Println("文件模式和权限:", fileInfo.Mode())

fmt.Println("文件大小:", fileInfo.Size())

fmt.Println("------读取文件的内容------")

data := make([]byte, 1000)

for{

if numBytes, err := file.Read(data);numBytes > 0{

fmt.Printf("%q, %v, %v", data[:numBytes], err, numBytes)

}else{

fmt.Println("output ok:")

break

}

}

}

// 输出结果

------文件操作------

文件绝对路径: D:/07.go/02.gostudy/goproject/src/com/gdzs/main/main.go

文件名: main

文件名称: main.go

C:\Users\12862

文件模式和权限: -rw-rw-rw-

文件大小: 2724

------读取文件的内容------

"package main\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"com.gdzs/goproject/src/com/gdzs/mystudy\"\r\n\t_\"github.com/gin-gonic/gin\"\r\n)\r\n\r\nfunc init(){\r\n\tfmt.Println(\"init函数执 行了\")\r\n}\r\n//“

文件的打开、创建、读取、写入、重命名、获取信息等操作

打开文件:os.Open创建文件:os.Create读取文件:句柄.Read(buffer)写入文件:句柄.Write(data) package mystudy

import (

"fmt"

"os"

_"path" // path只能处理一种路径\\

_"path/filepath" // filepath 可以处理相对复杂的分隔符 提供了相对路径和绝对路径的处理方法

)

//打开文件函数

func OpenFile(filePath string) *os.File {

fmt.Println("------打开文件------")

var filePhth string = filePath

// 打开文件:如果要以何种模式打开可以使用

// file, err := os.OpenFile("data.txt", os.O_RDONLY, 0644)

// os.O_RDONLY参数表示只读模式,0644是文件权限。如果文件打开成功,

// 将输出"File opened successfully.",否则输出错误信息。

file, err := os.Open(filePhth)

if err !=nil{

panic(err)

return nil

}

return file

}

// 创建文件

func CreateFile(fileName string) *os.File {

fmt.Println("------创建文件------")

file, err :=os.Create(fileName)

if err != nil {

panic(fmt.Sprintf("创建文件失败: %s", err))

}

return file

}

// 读取文件

func ReadFile(file os.File){

// 将指针移动到头部

_, err := file.Seek(0, 0)

buffer := make([]byte, 13)

numBytes, err := file.Read(buffer)

fmt.Println("读取文件大小:", numBytes, err)

fmt.Printf("文件内容:%q\n", buffer[:])

}

// 写入文件内容

func WriteFile(file *os.File){

fmt.Println("---写入文件内容---")

data := []byte("hello, World!")

numBytes, _ := file.Write(data)

fmt.Println(numBytes)

}

// 重命名文件

func RenameFile(oldName string, fileName string){

err := os.Rename(oldName, fileName)

fmt.Println("err:", err)

}

// 获取文件信息

func GetFileInfo(fileName string){

fileInfo, _ := os.Stat(fileName)

fmt.Println("文件名:", fileInfo.Name())

fmt.Println("文件大小", fileInfo.Size())

fmt.Println("修改时间", fileInfo.ModTime())

}

func DemoFile01() {

fmt.Println("------文件操作------")

defer func(){

if r:= recover();r != nil{

fmt.Println("Panic:", r)

return

}

}()

var filePath string = "D:\\07.go\\02.gostudy\\goproject\\src\\com\\gdzs\\main\\main.go"

// 获取文件信息

GetFileInfo(filePath)

file := OpenFile(filePath)

if file != nil{

fmt.Println(file)

}else{

fmt.Println("打开文件失败")

}

// 创建文件

createFile := CreateFile("gdzs.go")

fmt.Println(createFile)

// 写入数据

WriteFile(createFile)

// 读取文件

ReadFile(*createFile)

createFile.Close()

RenameFile("gdzs.go", "gdzs.txt")

}

// 输出结果

------文件操作------

文件名: main.go

文件大小 2724

修改时间 2024-04-15 15:27:30.7824836 +0800 CST

------打开文件------

&{0xc0003ff180}

------创建文件------

&{0xc0003ff400}

---写入文件内容---

13

读取文件大小: 13

文件内容:"hello, World!"

err:

2.io流操作文件

文本作者公众号:

2.1io流简介

io流一般用于处理文件不是很大的。 有了os模块可以操作文件,那么为什么还需要io流呢? IO 流适用于许多不同的场景,特别是在处理数据流、文件和网络传输时。以下是一些适合使用 IO 流的常见场景:

文件读写:IO 流提供了读取和写入文件数据的高级接口,可以逐块地读取或写入文件内容。这对于处理大型文件或需要逐行读取文本文件等情况非常有用。网络传输:在网络编程中,IO 流用于读取和写入网络套接字数据。通过使用 net.Conn 类型的 IO 流,您可以从网络连接中读取数据,或将数据写入到网络连接中,实现与远程服务器的通信。数据流处理:IO 流适用于处理连续的数据流,而不是一次性加载所有数据。这在处理大量数据或需要实时处理数据的情况下非常有用。通过逐块地读取和处理数据流,可以降低内存消耗,并提高处理效率。数据转换处理:IO 流提供了灵活的接口和方法,可以对数据进行转换和处理。通过组合多个 IO 流、使用缓冲区、使用编码解码器等,可以实现各种数据转换和处理操作,如压缩、加密、解析等。多路复用:IO 流支持多路复用,可以同时处理多个数据源或数据目标。通过使用并发或异步的方式,可以同时处理多个 IO 流,从而提高系统的并发性和效率。

os.File 类型实现了 io.Reader、io.Writer、io.Closer 等接口,这使得 os.File 可以通过 Read()、Write() 等方法进行数据的读取和写入。这样,我们可以使用 os 包打开文件,然后使用 io 包提供的通用接口和函数来处理文件数据。

2.2IO流操作文件实战

io的两种读取方式:使用io/ioutil模块 ioutil.ReadFile(filePath):这个方法已经内置了关闭和打开文件,所以这里不需要关注文件打开关闭,可以直接调用读取方法读取另外一只是一行行 读使用io需要写文件的读写与关闭file2, _ := os.Open(filePath)

defer file2.Close()

// 创建一个流

reader := bufio.NewReader(file2)

for{

str, err := reader.ReadString('\n')

if err == nil || err == io.EOF{

fmt.Println(str)

}

if err == io.EOF {

fmt.Println("---读完了---")

break

} else if err != nil {

fmt.Println("Failed to read file:", err)

break

}

}

代码实践package mystudy

// io流读取文件

import (

"fmt"

"io/ioutil"

"os"

"bufio"

"io"

)

func DemoIoFile(){

var filePath string = "D:/07.go/02.gostudy/gdzs.txt"

defer func(){

if err := recover();err != nil{

fmt.Println("报异常:", err)

return

}

}()

//io读取文件:自带了文件的开关

file, err := ioutil.ReadFile(filePath)

if err != nil {

fmt.Println("读取出错,错误为:", err)

}

fmt.Printf("%v\n",string(file))

//带有缓存的读取方式

fmt.Println("---带有缓存的读取方式---")

file2, _ := os.Open(filePath)

fmt.Println(file2)

defer file2.Close()

// 创建一个流

reader := bufio.NewReader(file2)

for{

str, err := reader.ReadString('\n')

if err == nil || err == io.EOF{

fmt.Println(str)

}

if err == io.EOF {

fmt.Println("---读完了---")

break

} else if err != nil {

fmt.Println("Failed to read file:", err)

break

}

}

}

2.3其他的用途:

标准输入读取: package main

import (

"bufio"

"fmt"

"os"

)

func main() {

scanner := bufio.NewScanner(os.Stdin)

for scanner.Scan() {

line := scanner.Text()

fmt.Println("Input:", line)

}

if err := scanner.Err(); err != nil {

fmt.Println("Error:", err)

}

}

标准输出写入: package main

import (

"bufio"

"fmt"

"os"

)

func main() {

writer := bufio.NewWriter(os.Stdout)

message := "Hello, World!"

_, err := writer.WriteString(message)

if err != nil {

fmt.Println("Error:", err)

}

err = writer.Flush()

if err != nil {

fmt.Println("Error:", err)

}

}

网络通信中的缓冲读取: package main

import (

"bufio"

"fmt"

"net"

)

func main() {

conn, err := net.Dial("tcp", "example.com:80")

if err != nil {

fmt.Println("Error:", err)

return

}

defer conn.Close()

reader := bufio.NewReader(conn)

for {

line, err := reader.ReadString('\n')

if err != nil {

fmt.Println("Error:", err)

break

}

fmt.Println("Received:", line)

}

}

字符串缓冲读写: package main

import (

"bufio"

"fmt"

"strings"

)

func main() {

input := "Hello\nWorld\n"

reader := bufio.NewReader(strings.NewReader(input))

for {

line, err := reader.ReadString('\n')

if err != nil {

break

}

fmt.Println("Line:", line)

}

writer := bufio.NewWriter(strings.NewWriter())

message := "Hello, World!"

_, err := writer.WriteString(message)

if err != nil {

fmt.Println("Error:", err)

}

err = writer.Flush()

if err != nil {

fmt.Println("Error:", err)

}

output := writer.String()

fmt.Println("Output:", output)

}

3.文件写入综合实践

需要os.OpenFile()打开文件使用bufio写入内容package mystudy

// 文件写入

import "fmt"

import "os"

import "bufio"

func DemoWriteFile(){

var filePath = "D:/07.go/02.gostudy/gdzs.txt"

file, _:= os.OpenFile(filePath, os.O_RDWR | os.O_APPEND | os.O_CREATE, 0666)

writer := bufio.NewWriter(file)

for i:=0; i<=6; i++{

writer.WriteString("你好,中国")

}

writer.Flush()

fmt.Println(file)

defer file.Close()

}

参数详解 在 Go 语言中,os.OpenFile() 函数的第二个参数是一个标志位,用于指定文件的打开模式和权限。在您提到的例子中,0666 是一个表示文件打开模式和权限的八进制数。 在八进制数 0666 中,每个数字代表一组权限,共有四组权限:所有者权限、所有者所属组权限、其他人权限以及特殊权限。每组权限由三个二进制位表示,分别代表读、写和执行权限。 具体解释如下:

第一组(最高位)代表所有者权限。0 表示没有权限,6 表示所有者具有读和写权限。第二组代表所有者所属组权限。6 表示所有者所属组具有读和写权限。第三组代表其他人权限。6 表示其他人具有读和写权限。第四组(最低位)代表特殊权限,例如粘着位、SGID 位、SUID 位等。在这种情况下,0 表示没有特殊权限。 将 0666 转换为二进制表示为 110 110 110,意味着所有者、所有者所属组和其他人都具有读和写权限。 因此,os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE, 0666) 使用 0666 打开模式表示创建文件(如果文件不存在)并为该文件设置读和写权限,使得所有者、所有者所属组和其他人都可以读取和写入该文件。 需要注意的是,使用 0666 权限设置可能会导致较为宽松的权限,具体权限设置应根据实际需求和安全性考虑进行选择。 st权限 在文件权限中,“st” 表示文件的 Set UID (SUID) 和 Set GID (SGID) 权限。

Set UID (SUID):当一个可执行文件被设置了 SUID 权限时,无论谁执行该文件,都会暂时以该文件的所有者身份来执行。这意味着执行者将具有该文件所有者的权限和特权。SUID 权限对于某些需要特定权限才能执行的程序非常有用,例如密码更改程序 passwd。Set GID (SGID):当一个可执行文件被设置了 SGID 权限时,无论谁执行该文件,都会以该文件所属组的身份来执行。与 SUID 类似,SGID 也允许执行者暂时获得执行文件所属组的权限和特权。 这些权限标志通常在文件的权限位中表示为 “s” 或 “S”,具体取决于执行者是否同时具有执行权限。小写 “s” 表示设置了 SUID 或 SGID 权限,并且对应的执行权限也被设置。大写 “S” 表示设置了 SUID 或 SGID 权限,但对应的执行权限未被设置。 以下是一些示例:-rwsr-xr-x:具有 SUID 权限的可执行文件,所有者具有读、写和执行权限,组和其他人具有执行权限。-rwxr-sr-x:具有 SGID 权限的可执行文件,所有者具有读、写和执行权限,组具有读、执行权限,其他人具有执行权限。 设置 SUID 和 SGID 权限需要谨慎,以确保文件的安全性和权限控制。

4.文件复制

复制的原理就是,从一个文件中读取数据,然后写入新的文件中,这里使用ioutil包实现

package mystudy

// 文件复制

import (

f"fmt"

"io/ioutil"

)

func DemoFileCopy(){

f.Println("---文件复制---")

filePath1 := "gdzs.txt"

filePath2 := "demo02.txt"

// 读取文件

content, err:= ioutil.ReadFile(filePath1)

f.Println(content)

// 写入文件

err = ioutil.WriteFile(filePath2, content, 0666)

if err != nil{

f.Println("复制文件-写入错误", err)

}

}

5.os包和bufio包操作文件的区别

5.1概述

os包和bufio包是Go语言标准库中用于文件操作的两个不同的包,它们有一些区别和不同的用途。 os 包: os包提供了与操作系统交互的功能,包括文件和目录的创建、打开、读取、写入、删除等操作。它提供了底层的文件操作接口,可以直接操作文件描述符。os包中的函数返回的错误类型是error,需要显式地进行错误处理。它适用于对文件进行较底层、原始的读写操作。 bufio 包: bufio包提供了带缓冲功能的 I/O 操作,可以提高文件读写的效率。它基于io.Reader和io.Writer接口,提供了带缓冲的读取(bufio.Reader)和写入(bufio.Writer)操作。bufio包内部维护了一个缓冲区,可以减少对底层文件的实际读写次数。它还提供了一些便利的函数,如按行读取文本文件等。bufio包中的函数返回的错误类型是error,需要显式地进行错误处理。它适用于高效的文件读写操作。

5.2代码演示

示例代码: 使用 os 包进行文件读写:

package main

import (

"fmt"

"log"

"os"

)

func main() {

file, err := os.OpenFile("filename.txt", os.O_WRONLY|os.O_CREATE, 0644)

if err != nil {

log.Fatal(err)

}

defer file.Close()

data := []byte("Hello, World!")

_, err = file.Write(data)

if err != nil {

log.Fatal(err)

}

readData := make([]byte, 1024)

_, err = file.Read(readData)

if err != nil {

log.Fatal(err)

}

fmt.Printf("读取的数据:%s\n", readData)

}

使用 bufio 包进行文件读写:

package main

import (

"bufio"

"fmt"

"log"

"os"

)

func main() {

file, err := os.OpenFile("filename.txt", os.O_WRONLY|os.O_CREATE, 0644)

if err != nil {

log.Fatal(err)

}

defer file.Close()

writer := bufio.NewWriter(file)

data := []byte("Hello, World!")

_, err = writer.Write(data)

if err != nil {

log.Fatal(err)

}

writer.Flush()

reader := bufio.NewReader(file)

readData, err := reader.ReadString('\n')

if err != nil {

log.Fatal(err)

}

fmt.Printf("读取的数据:%s\n", readData)

}

注意,在以上的示例代码中,我们使用了不同的读取方式,os包直接调用了file.Read方法读取数据,而bufio包通过bufio.NewReader创建了一个带缓冲的读取器,并使用reader.ReadString按行读取数据。 简而言之,os包适用于较底层的文件读写操作,而bufio包提供了更高级、带缓冲的文件读写功能。选择使用哪个包取决于您的具体需求和场景。

5.3特点和用法

当涉及到文件操作时,os包和bufio包在功能和用途上有一些区别,下面将进一步详细介绍它们的特点和用法。 os 包的特点和用法:

os包提供了一组函数,用于创建、打开、读取、写入、删除和操作文件和目录。它提供了底层的文件操作接口,可以直接操作文件描述符。os包中的函数返回的错误类型是error,需要显式地进行错误处理。os包提供的函数可以用于读取和写入任意类型的数据,但需要手动处理数据的格式和解析。适用于对文件进行较底层、原始的读写操作。提供了文件的权限设置、文件信息获取等功能。 bufio 包的特点和用法:bufio包提供了带缓冲功能的 I/O 操作,可以提高文件读写的效率。它基于io.Reader和io.Writer接口,提供了带缓冲的读取和写入操作。bufio包内部维护了一个缓冲区,可以减少对底层文件的实际读写次数,提高性能。bufio包提供了一些便利的函数,如按行读取文本文件、读取指定字节数的数据等。bufio包中的函数返回的错误类型是error,需要显式地进行错误处理。适用于高效的文件读写操作,特别是处理大量数据时。

使用 os 包读取文件的所有行:

package main

import (

"bufio"

"fmt"

"log"

"os"

)

func main() {

file, err := os.Open("filename.txt")

if err != nil {

log.Fatal(err)

}

defer file.Close()

scanner := bufio.NewScanner(file)

for scanner.Scan() {

line := scanner.Text()

fmt.Println(line)

}

if err := scanner.Err(); err != nil {

log.Fatal(err)

}

}

使用 bufio 包写入文件的所有行:

package main

import (

"bufio"

"log"

"os"

)

func main() {

file, err := os.OpenFile("filename.txt", os.O_WRONLY|os.O_CREATE, 0644)

if err != nil {

log.Fatal(err)

}

defer file.Close()

writer := bufio.NewWriter(file)

lines := []string{"Line 1", "Line 2", "Line 3"}

for _, line := range lines {

_, err := writer.WriteString(line + "\n")

if err != nil {

log.Fatal(err)

}

}

writer.Flush()

}

5.4问题

100G的文件,内存只有8G 使用那种方式读取呢? 那么最好的选择是使用逐行读取的方式,以避免将整个文件加载到内存中。可以使用bufio.Scanner来按行读取文件。bufio.Scanner会逐行地读取文件内容,而不会一次性将整个文件加载到内存中。这种方法可以在有限的内存下有效地处理大型文件。 示例代码:package main

import (

"bufio"

"fmt"

"log"

"os"

)

func main() {

file, err := os.Open("largefile.txt")

if err != nil {

log.Fatal(err)

}

defer file.Close()

scanner := bufio.NewScanner(file)

for scanner.Scan() {

line := scanner.Text()

// 在这里处理每一行的数据

fmt.Println(line)

}

if err := scanner.Err(); err != nil {

log.Fatal(err)

}

}

通过逐行读取文件,可以在有限的内存下处理大型文件,并逐行对文件内容进行处理,而不会超出内存限制。

精彩内容

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: