【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)
}
}
通过逐行读取文件,可以在有限的内存下处理大型文件,并逐行对文件内容进行处理,而不会超出内存限制。
精彩内容
大家都在找:
golang:golang gmp模型
开发语言:开发语言有哪几种
后端:后端开发工资一般多少
发表评论