0


go语言的成神之路-筑基篇-对文件的操作

一、对文件的读写

在 Go 语言中,

io

包提供了基本的接口,用于 I/O 原语。它的主要目的是将这些原语抽象化,使得它们在不同的实现中可以通用。

Reader

接口

以下是一个对文件中内容读取的一个示例:

package main

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

func main() {
    // 打开文件 text.txt,如果打开失败,打印错误信息并返回
    file, err := os.Open("./text.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    // 确保文件在函数结束时关闭
    defer file.Close()
    // 定义一个长度为 128 的字节数组作为缓冲区
    var buf [128]byte
    // 存储文件内容的字节切片
    var content []byte
    for {
        // 从文件中读取数据到缓冲区,n 表示读取的字节数
        n, err := file.Read(buf[:])
        // 如果到达文件末尾,跳出循环
        if err == io.EOF {
            break
        }
        // 如果读取过程中出现错误,打印错误信息并返回
        if err != nil {
            fmt.Println(err)
            return
        }
        // 将读取到的数据添加到 content 切片中
        content = append(content, buf[:n]...)
    }
    // 将字节切片转换为字符串并打印
    fmt.Println(string(content))
}

Writer接口

以下是写入文件的操作:

注:每次写入的时候原文件中的内容都会被覆盖。

// Writer接口的定义和实现
package main

import (
    "fmt"
    "os"
)

func main() {
    // 打开文件 text.txt,如果文件不存在则创建,如果文件存在则清空内容
    file, err := os.Create("./text2.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    // 确保文件在函数结束时关闭
    defer file.Close()

    // 定义一个字符串
    str := "Hello,World!"
    // 将字符串转换为字节切片
    data := []byte(str)
    // 将字节切片写入文件
    _, err = file.Write(data)
    // 如果写入过程中出现错误,打印错误信息并返回
    if err != nil {
        fmt.Println(err)
        return
    }
}

写入一个 Hello,World!

写入一个”你好世界!“

可以看出原来文件中的文本被替换了。

copy接口

以下是复制文件的操作:

// io.Copy的使用
package main

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

func main() {
    // 打开文件 text.txt,如果文件不存在则创建,如果文件存在则清空内容
    begin, err := os.Open("./text2.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    // 确保文件在函数结束时关闭
    defer begin.Close()

    // 打开文件 text2.txt,如果文件不存在则创建,如果文件存在则清空内容
    end, err := os.Create("./text3.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    // 确保文件在函数结束时关闭
    defer end.Close()

    // 将文件 text.txt 的内容复制到文件 text2.txt 中
    _, err = io.Copy(end, begin)
    // 如果复制过程中出现错误,打印错误信息并返回
    if err != nil {
        fmt.Println(err)
        return
    }
}

begin中的内容会自动覆盖end中的内容。

bufio的使用

常见的方法如下:

// bufio的使用
package main

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

func wr() {
    // 参数2 是文件的打开方式,os.O_CREATE|os.O_WRONLY|os.O_APPEND 表示创建文件并以写入模式打开,文件不存在则创建,文件存在则在文件末尾追加内容
    // 参数3 是文件的权限,0666 表示文件所有者、组和其他用户都有读写权限
    // w写 r读 a追加 x执行
    file, err := os.OpenFile("./text.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer file.Close()

    // 获取writer对象
    writer := bufio.NewWriter(file)
    writer.WriteString("hello bufio")

    // 刷新缓冲区
    writer.Flush()
}

func rd() {
    file, err := os.Open("./text.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)

    for {
        line, _, err := reader.ReadLine()
        if err != io.EOF {
            fmt.Println(err)
            break
        }
        if err != nil {
            fmt.Println(err)
            return
        }
        fmt.Println(string(line))
    }
}

func main() {
    wr()
}

以这种方式进行读写不会覆盖原来的文件

读取文本文件的时候是按行读取的

ioutil库

// ioutil的使用
package main

import (
    "fmt"
    "io/ioutil"
)

func wr() {
    err := ioutil.WriteFile("./text.txt", []byte("hello ioutil"), 0666)
    if err != nil {
        fmt.Println(err)
        return
    }
}

func re() {
    content, err := ioutil.ReadFile("./text.txt")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println(string(content))
}
func main() {
    wr()
    re()
}

这个工具库相对于其他的工具库更为简单。相应的函数已经被很好的打包完成了。

二、cat命令

package main

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

// cat 函数接收一个 bufio.Reader 指针作为输入,用于读取文件或标准输入的内容
func cat(r *bufio.Reader) {
    // 开始一个无限循环,用于逐行读取数据
    for {
        // 从 bufio.Reader 中读取一行数据,直到遇到换行符 '\n',存储在 buf 中,并将可能的错误存储在 err 中
        buf, err := r.ReadBytes('\n')
        // 如果读取到文件末尾,打印错误信息并退出循环
        if err == io.EOF {
            fmt.Println(err)
            break
        }
        // 将读取到的一行数据输出到标准输出
        fmt.Fprintf(os.Stdout, "%s", buf)
    }
}

func main() {
    // 解析命令行参数
    flag.Parse()
    if flag.NArg() == 0 {
        // 从标准输入读取数据并输出到标准输出
        cat(bufio.NewReader(os.Stdin))
    }
    // 依次处理每个文件
    for i := 0; i < flag.NArg(); i++ {
        // 打开文件
        f, err := os.Open(flag.Arg(i))
        if err!= nil {
            fmt.Fprintf(os.Stderr, "cat: %s: %s\n", flag.Arg(i), err)
            continue
        }
        // 读取文件内容并输出到标准输出
        cat(bufio.NewReader(f))
        // 关闭文件
        f.Close()
    }
}

上述代码中,

cat

函数的主要功能是从

bufio.Reader

中逐行读取数据并输出到标准输出。在

for

循环中,使用

r.ReadBytes('\n')

方法读取一行数据,当遇到文件结束符

io.EOF

时,打印错误信息并退出循环,否则将读取的数据输出到标准输出。在

main

函数中,首先解析命令行参数,若没有命令行参数,则从标准输入读取数据;若有命令行参数,则依次打开文件,调用

cat

函数读取文件内容并输出,最后关闭文件。

**注:在

cat

函数中,当遇到

io.EOF

时,打印错误信息可能不是最佳做法,因为

EOF

不是错误,而是文件结束的标志。可以考虑修改为不打印错误信息,仅退出循环。**

如果文件中有内容就会打印出文件中的内容。

如果直接执行go run mian.go会打印输出用户输入的内容。

三、包

在 Go 语言中,包(package)是组织代码的一种方式,它可以将相关的函数、变量和类型组合在一起,以便于代码的管理、复用和维护。以下是关于 Go 语言包的一些重要信息:

1. 包的声明

在 Go 文件的开头,使用

package

关键字来声明包的名称。

package main
  • package main 是一个特殊的包,它表示该文件是一个可执行程序的入口点。
  • 对于其他包,可以使用其他名称,如 package utilspackage math

2. 导入包

使用

import

语句来导入其他包。

import (
    "fmt"
    "os"
    "github.com/yourusername/yourpackage"
)
  • 导入标准库中的包,如 fmtos
  • 导入第三方包,如 github.com/yourusername/yourpackage

3. 包的可见性

  • 在 Go 中,标识符(函数、变量、类型)的名称首字母大小写决定了其可见性:
  • 首字母大写的标识符是导出的,可以被其他包访问。
  • 首字母小写的标识符是未导出的,只能在当前包内使用。
package mypackage

// 导出的函数
func ExportedFunction() {
}

// 未导出的函数
func unexportedFunction() {
}

在另一个包中,可以调用

mypackage.ExportedFunction()

,但不能调用

mypackage.unexportedFunction()

4. 包的初始化

包可以包含一个

init

函数,它会在包被导入时自动执行。

package mypackage

import "fmt"

func init() {
    fmt.Println("Initializing mypackage")
}
  • 一个包可以有多个 init 函数,它们会按照声明的顺序执行。

5. 标准库包

Go 标准库包含了许多有用的包,例如:

  • fmt:格式化输入和输出。
  • os:提供操作系统功能,如文件操作、环境变量等。
  • io:提供基本的 I/O 操作接口。
  • bufio:提供缓冲的 I/O 操作。
  • net:提供网络编程功能。
  • sync:提供同步原语,如互斥锁、读写锁等。

6. 第三方包

可以使用

go get

命令来获取第三方包

比如在gin框架学习中引用的gin包

import "github.com/gin-gonic/gin"

7. 包的组织

  • 通常,一个目录对应一个包。
  • 包的名称应该与目录名称相同,除非使用 package main

8. 包的别名

可以为导入的包设置别名。

import (
    f "fmt"
)
  • 这里将 fmt 包的别名设置为 f,可以使用 f.Println() 来调用 fmt.Println()

9. 包的路径

  • 包的路径是其在文件系统或远程仓库中的位置。
  • 对于标准库,路径是 std 包的一部分,如 fmt 包的路径是 std/fmt
  • 对于第三方包,路径是其在远程仓库中的位置,如 github.com/gin-gonic/gin

10. 包的版本管理

  • Go 1.11 及以后的版本支持模块(module),可以使用 go.mod 文件来管理依赖的版本。
  • 例如,创建一个 go.mod 文件:
module mymodule

go 1.14

require github.com/gin-gonic/gin v1.7.4

这将确保使用

github.com/gin-gonic/gin

v1.7.4

版本。

以下是一个完整的示例,展示了包的使用:

package main

import (
    "fmt"
    "mypackage"
)

func main() {
    // 使用标准库的 fmt 包
    fmt.Println("Hello, World!")
    // 使用自定义包 mypackage
    mypackage.ExportedFunction()
}

在这个示例中:

  • 导入了 fmt 标准库包和 mypackage 自定义包。
  • main 函数中,调用了 fmt.Println()mypackage.ExportedFunction()

通过合理使用包,可以将代码组织得更加清晰、易于维护和复用,同时利用 Go 语言强大的标准库和丰富的第三方库资源。

四、go mod

go mod

是 Go 语言从 1.11 版本开始引入的模块管理工具,它允许开发者更好地管理项目的依赖关系,而不再依赖于

GOPATH

环境变量。

1. 初始化一个新的模块

使用

go mod init

命令来初始化一个新的模块。例如:

go mod init example.com/myproject

这将创建一个

go.mod

文件,内容如下:

module example.com/myproject

go 1.14
  • module 后面的部分是模块的名称,通常是一个唯一的标识符,如域名加项目名。
  • go 后面的部分是 Go 语言的版本。

2. 依赖管理

当你导入一个新的包时,

go mod

会自动更新

go.mod

文件。例如:

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    gin.Default()
}

运行

go build

go run

时,

go mod

会自动更新

go.mod

文件,添加所需的依赖:

module example.com/myproject

go 1.14

require github.com/gin-gonic/gin v1.7.4

3. 查看依赖关系

使用

go list -m all

命令可以查看所有的依赖关系:

go list -m all

4. 下载依赖

使用

go mod download

命令可以下载所有的依赖:

go mod download

5. 清理未使用的依赖

使用

go mod tidy

命令可以清理未使用的依赖:

go mod tidy

6. 替换依赖

如果需要替换一个依赖,可以在

go.mod

文件中使用

replace

指令。例如:

replace github.com/oldpackage => github.com/newpackage v1.2.3

7. 版本管理

  • go mod 会自动选择依赖的最新版本,但可以使用 require 指令指定版本。例如:
require github.com/gin-gonic/gin v1.7.4
  • 可以使用 @ 符号指定特定的版本,如 v1.7.4v1.7.4+incompatiblev1.7.4-pre

8. 私有模块

对于私有模块,可以使用

replace

指令或环境变量

GOPRIVATE

来管理。例如:

replace private.com/myproject => /path/to/local/project

9. 构建和测试

  • go buildgo test 命令会自动使用 go.mod 中的依赖信息。

10. 示例

以下是一个完整的

go.mod

文件示例:

module example.com/myproject

go 1.14

require (
    github.com/gin-gonic/gin v1.7.4
    github.com/somepackage v1.2.3
)

replace github.com/oldpackage => github.com/newpackage v1.2.3

总结

  • go mod init 初始化模块。
  • go mod tidy 清理未使用的依赖。
  • go mod download 下载依赖。
  • go mod edit 编辑 go.mod 文件。
  • go list -m all 查看依赖。

使用

go mod

可以让 Go 项目的依赖管理更加灵活和方便,避免了

GOPATH

的限制,提高了项目的可维护性和可移植性。


本文转载自: https://blog.csdn.net/2302_80329073/article/details/144172948
版权归原作者 ●VON 所有, 如有侵权,请联系我们删除。

“go语言的成神之路-筑基篇-对文件的操作”的评论:

还没有评论