首页 > 其他分享 >(10-3)文件操作:包io

(10-3)文件操作:包io

时间:2024-05-28 10:59:02浏览次数:20  
标签:10 读取 err 文件 接口 io

10.3  包io

在Go 语言中,io是一个重要的标准库包,提供了一系列内置接口和方法,用于处理输入、输出流操作。包io中包含的常用接口如表10-1所示。

表10-1  包io中包含的常用接口

接口名称

描述

io.Reader

代表可以读取数据的对象,定义了一个 Read 方法

io.Writer

代表可以写入数据的对象,定义了一个 Write 方法

io.Closer

代表可以关闭的对象,定义了一个 Close 方法

io.Seeker

代表可以定位的对象,定义了一个 Seek 方法

io.ReaderAt

代表可以从指定位置读取数据的对象,定义了一个 ReadAt 方法

io.WriterAt

代表可以从指定位置写入数据的对象,定义了一个 WriteAt 方法

注意:除了以上列出的接口之外,io 包还定义了一些其他接口,例如 io.ReadCloser、io.WriteCloser、io.ReadSeeker、io.WriteSeeker 等,这些接口都是由上述基本接口组合而成的。

10.3.1  io.Reader和io.Writer

在Go语言中,io.Reader和io.Writer是两个非常重要的接口。在这两个接口中提供了一些内置方法,用于在文件中实现读取或写入数据。

1. io.Reader

在Go语言中,接口io.Reader用于从流中读取数据。在下表10-2中列出了接口io.Reader中的内置方法的和功能信息。

表10-2  接口io.Reader中的内置方法的和功能信息

方法名称

方法签名

功能描述

Read

func (T) Read(b []byte) (n int, err error)

从数据源中读取数据到缓冲区b中,返回实际读取的字节数和是否有错误发生。如果返回值的字节数小于缓冲区长度,则表示读取结束。

ReadAtLeast

func (T) ReadAtLeast(b []byte, min int) (n int, err error)

从数据源中读取至少min个字节的数据到缓冲区b中,返回实际读取的字节数和是否有错误发生。如果返回值的字节数小于min,则表示读取不足。

ReadFull

func (T) ReadFull(b []byte, min int) (n int, err error)

从数据源中读取指定长度的数据到缓冲区b中,返回实际读取的字节数和是否有错误发生。如果返回值的字节数小于指定长度,则表示读取不足。

表10-2中的方法都是通过实现了io.Reader接口的类型来调用的。我们可以根据自己的需要选择不同的方法来读取数据。

例如在下面的格式中,io.Reader接口定义了方法Read(),用于从数据源中读取数据。

type Reader interface {

    Read(p []byte) (n int, err error)

}

其中,p表示读取数据的缓冲区,n表示实际读取的字节数,err表示是否有错误发生。如果err == io.EOF,表示已经读取到文件末尾。如果返回其他错误,则说明在读取过程中出现了错误。

假设有一个记事本文件“filename.txt”,里面的内容如图10-1所示。

图10-1  文件“filename.txt”中的内容

实例10-2:读取指定文件中的内容(源码路径:Go-codes\10\read.go

实例文件read.go的具体实现代码如下所示。

import (

"fmt"

"io"

"os"

)

func main() {

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

if err != nil {

fmt.Println("Error:", err)

return

}

defer file.Close()

buf := make([]byte, 1024) // 创建读取数据的缓冲区

for {

n, err := file.Read(buf) // 从文件中读取数据到缓冲区

if n == 0 {

break // 读取结束

}

if err != nil && err != io.EOF {

fmt.Println("Error:", err)

return

}

fmt.Print(string(buf[:n])) // 输出缓冲区中的数据

}

}

对上述代码的具体说明如下:

  1. 首先通过函数os.Open()打开一个名为test.txt的文本文件,并将其赋值给file变量。
  2. 然后创建一个大小为1024字节的缓冲区来读取文件中的数据。
  3. 在for循环中,不断地从文件中读取数据到缓冲区中,并将实际读取的字节数保存到n变量中。如果读取到文件末尾,则退出循环;如果读取过程中发生了错误,则输出错误信息并退出程序。
  4. 最后,通过函数string()将缓冲区中的字节转换为字符串,并输出到控制台。

执行后会输出:

4月28日消息,天齐锂业公告,一季度实现营业收入114.49亿元,同比增长117.77%;净利润48.75亿元,同比增长46.49%;基本每股收益2.97元。

2. io.Writer写入数据

在Go语言中,接口io.Writer用于向流中写入数据。在下表10-3中列出了接口io.Writer中的内置方法的和功能信息。

表10-2  接口io.Writer中的内置方法的和功能信息

方法名称

方法签名

功能描述

Write

func (T) Write(b []byte) (n int, err error)

将缓冲区b中的数据写入到数据源中,返回实际写入的字节数和是否有错误发生。如果返回值的字节数小于缓冲区长度,则表示写入结束。

WriteString

func (T) WriteString(s string) (n int, err error)

将字符串s写入到数据源中,返回实际写入的字节数和是否有错误发生。如果返回值的字节数小于字符串长度,则表示写入结束。

WriteAt

func (T) WriteAt(b []byte, off int64) (n int, err error)

将缓冲区b中的数据从指定位置off开始写入到数据源中,返回实际写入的字节数和是否有错误发生。如果返回值的字节数小于缓冲区长度,则表示写入结束。

表10-2中的方法都是通过实现了io.Writer接口的类型来调用的,我们可以根据自己的需要选择不同的方法来写入数据。

实例10-3:将某个文件中的内容复制到另外一个文件(源码路径:Go-codes\10\copy.go

实例文件copy.go的具体实现代码如下所示。

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

func main() {
	source, err := os.Open("filename.txt") // 打开源文件
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer source.Close()

	destination, err := os.Create("destination.txt") // 创建目标文件
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer destination.Close()

	reader := io.Reader(source)
	writer := io.Writer(destination)
	_, err = io.Copy(writer, reader) // 将源文件中的数据复制到目标文件中
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("Copy success!")
}

对上述代码的具体说明如下:

  1. 首先通过函数os.Open()打开了一个名为source.txt的文本文件,并将其赋值给变量source。
  2. 接着,通过函数os.Create()创建了一个名为destination.txt的记事本文件,并将其赋值给destination变量。
  3. 然后,分别创建了一个源文件的读取器和一个目标文件的写入器。
  4. 在函数io.Copy()中,将源文件中的数据复制到目标文件中,并打印输出复制成功的信息。

执行后会输出:

Copy success!

成功将文件filename.txt中的内容复制到文件destination.txt中,如图10-2所示。

图10-2  文件destination.txt中的内容

10.3.2  io.ReaderAt和io.WriterAt

在Go语言中,通过接口io.ReaderAt和io.WriterAt可以从指定位置读取/写入数据。

1. io.ReaderAt

接口io.ReaderAt定义了一个读取指定位置数据的方法,该接口适用于需要随机访问文件或其他数据源的情况。在接口io.ReaderAt中包含了一个内置函数ReadAt(),功能是从指定偏移量处读取数据到缓冲区中。函数ReadAt()的原型如下所示。

func (r ReaderAt) ReadAt(p []byte, off int64) (n int, err error)

  1. 参数p []byte:缓冲区,读取的数据将被写入到这个参数指向的字节数组中。
  2. 参数off int64:偏移量,从文件的哪个位置开始读取数据。
  3. 返回值:读取的字节数和可能出现的错误。

通过使用接口io.ReaderAt,可以更加灵活地访问文件或其他数据源中的数据。例如,在处理大文件时,可以使用接口io.ReaderAt分块读取数据,以减少内存占用,提高程序的性能。

2. io.WriterAt

接口io.WriterAt定义了一个向指定位置写入数据的方法,该接口适用于需要随机访问文件或其他数据源的情况。在接口io.WriterAt中包含了一个内置函数WriteAt(),功能是将缓冲区中的数据写入到指定偏移量的位置。函数WriteAt()的原型如下所示。

func (w WriterAt) WriteAt(p []byte, off int64) (n int, err error)
  1. p []byte:缓冲区,需要写入的数据存储在这个参数指向的字节数组中。
  2. off int64:偏移量,从文件的哪个位置开始写入数据。
  3. 返回值:为写入的字节数和可能出现的错误。

通过使用接口io.WriterAt,可以更加灵活地向文件或其他数据源中写入数据。例如,在分布式系统中,可以使用接口io.WriterAt将数据按照某种规则写入多个节点上,以实现高效的数据存储和访问。

假设文件example.txt中的内容如图10-3所示,在下面的实例中,使用接口io.ReaderAt和接口io.WriterAt将文件中指定位置的文本修改为新的内容。

图10-3  文件example.txt中的内容

实例10-4:将文件中指定位置的文本修改为新的内容(源码路径:Go-codes\10\mod.go

实例文件mod.go的具体实现代码如下所示。

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

func main() {
	// 打开文件并创建读写器
	file, err := os.OpenFile("example.txt", os.O_RDWR, 0666)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	defer file.Close()

	// 读取原始文本
	offset := int64(10) // 修改文本的起始位置
	size := int64(5)    // 修改文本的长度
	buf := make([]byte, size)
	n, err := file.ReadAt(buf, offset)
	if err != nil && err != io.EOF {
		fmt.Println("Error:", err)
		return
	}
	fmt.Printf("Original text: %s\n", buf[:n])

	// 写入新文本
	newText := []byte("hello")
	n, err = file.WriteAt(newText, offset)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Printf("Write %d bytes to file\n", n)
}

对上述代码的具体说明如下:

  1. 首先打开一个名为example.txt的记事本文件,并使用函数os.OpenFile()以读写方式打开,并指定了文件的字符编码格式为UTF-8。
  2. 然后,使用方法file.ReadAt()从文件的第10个字节处开始读取长度为5的文本内容,并将其赋值给buf变量。
  3. 接着,使用方法file.WriteAt()向文件的第10个字节处写入新文本"hello"。
  4. 最后,重新读取文件内容并输出。

执行后会输出:

Original text: 4月28日,天齐锂业公告,一季度实现营业收入114.49亿元,同比增长117.77%;净利润48.75亿元,同比增长46.49%;基本每股收益2.97元。

Write 5 bytes to file

New content: 4月28日hello,天齐锂业公告,一季度实现营业收入114.49亿元,同比增长117.77%;净利润48.75亿元,同比增长46.49%;基本每股收益2.97元。

此时文件example.txt中的内容如图10-4所示

图10-4  文件example.txt中的内容

10.3.3  接口io.Seeker

接口io.Seeker是 Go 语言标准库中的一个接口类型,它定义了一个用于查找和修改数据流中偏移量的方法。接口io.Seeker通过内置方法Seek()设置数据流中的偏移量。以下是接口io.Seeker的定义:

type Seeker interface {
    Seek(offset int64, whence int) (int64, error)
}

其中,方法Seek()中各个参数的说明如下:

  1. offset:相对于 whence 参数指定的位置的偏移量,可以为负数。
  2. whence:指定偏移量的基准位置,可以取值为 io.SeekStart(从数据流的开头开始计算)、io.SeekCurrent(从当前位置开始计算)或 io.SeekEnd(从数据流的结尾开始计算)。
  3. 返回值:有两个,新的偏移量和可能出现的错误。如果操作成功,则返回新的偏移量;否则,返回错误信息。

下面是一个使用接口io.Seeker的实例,功能是读取指定文件中的第二个字节并输出显示。

实例10-5:读取指定文件中的第二个字节并输出显示(源码路径:Go-codes\10\Seeker.go

实例文件Seeker.go的具体实现代码如下所示。

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

func main() {
	file, err := os.Open("example1.txt")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	_, err = file.Seek(1, io.SeekStart) // 将偏移量设置为 1(即跳过第一个字节)
	if err != nil {
		panic(err)
	}

	buf := make([]byte, 1)
	_, err = file.Read(buf)
	if err != nil {
		panic(err)
	}

	fmt.Printf("The second byte of the file is: %c\n", buf[0])
}

对上述代码的具体说明如下:

  1. 首先使用函数os.Open()打开一个名为 example.txt 的文件,并将其赋值给变量 file。
  2. 然后,使用方法file.Seek()将偏移量设置为 1,即跳过文件的第一个字节。
  3. 接着,使用方法file.Read()读取文件中的下一个字节,并将其输出到标准输出中。

假设 example.txt 文件包含以下内容:

Hello, world!

运行程序后会输出如下内容:

The second byte of the file is: e

之所以输出上述结果,是因为首先将偏移量设置为 1(即跳过第一个字符 H),然后从文件中读取下一个字节,即文件中的第二个字符 e,并将其输出到标准输出中。

注意:如果使用的是不同的文本文件或具有不同格式的文件,则输出结果可能与上述实例略有不同。

标签:10,读取,err,文件,接口,io
From: https://blog.csdn.net/asd343442/article/details/139260491

相关文章

  • Java-生成固定长度的随机字符串、随机字符串开头的ID、写入文件、读取文件
    packagecom.sgcc;importjava.io.*;importjava.text.DecimalFormat;importjava.util.ArrayList;importjava.util.List;importjava.util.Random;publicclassMain{publicstaticStringgenerateMixedString(intlength){Randomrandom=ne......
  • 深入解析Nginx Location匹配规则:顺序详解与最佳实践
    目录Nginxlocation匹配顺序详解总结与最佳实践 Nginx的location匹配顺序是Nginx配置中非常核心且重要的概念,它决定了Nginx如何处理进入服务器的请求。理解location匹配顺序不仅有助于优化Nginx的性能,还能确保网站或应用的正确运行。下面将详细阐述Nginx的location匹......
  • 打卡信奥刷题(22)用Scratch图形化工具信奥P1015 [NOIP1999 普及组] 回文数,写了一个好用
    P1015[NOIP1999普及组]回文数,用Scratch实现计算回文数,还写了一个比较好用的反序积木题目[NOIP1999普及组]回文数题目描述若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。例如:给定一个十进制数......
  • 力扣算法之1050. 合作过至少三次的演员和导演
    题解actor_id和director_id,类似一个坐标,只要出现三次或者三次以上就打印出来我的解SELECTactor_id,director_idFROMActorDirectorGROUPBYactor_id,director_idHAVINGCOUNT(1)>=3我的解注解同时分组,两个出现次数大于等于3的就是符合的,看了下,其他的思路和这个......
  • Visual Studio 智能代码插件:CodeGeeX
    前言 在软件开发领域,高效的编程助手一直是提升开发者效率和质量的关键。随着人工智能技术的不断发展,智能编程助手逐渐成为开发者们不可或缺的工具。其中,CodeGeeX作为一款专为VisualStudio设计的免费智能编程助手,凭借其强大的功能和便捷的使用体验,赢得了广大开发者的青睐。 ......
  • Nginx: stat() failed (13: permission denied)
    解决server{listen[::]:80default_server;#SSLconfiguration##listen443ssldefault_server;#listen[::]:443ssldefault_server;##Note:YoushoulddisablegzipforSSLtraffic.#S......
  • 这款信创FTP软件,可实现安全稳定的文件传输!
    信创,即信息技术应用创新,2018年以来,受“华为、中兴事件”影响,国家将信创产业纳入国家战略,并提出了“2+8+n”发展体系。“8”具体指金融、石油、电力、电信、交通、航空航天、医院、教育等主要行业。目前企业使用比较多的是FTP应用,随着技术的进步和企业需求的多元化,弊端也更加明显,需......
  • 如何安全地进行隔离网文件导出,最优方案出炉!
    越来越多的企业在网络建设时进行网络隔离,通常与提高安全性和控制风险有关。但网络隔离后,企业仍存在与外部客户、合作伙伴等数据交换的场景需求,即如何安全进行隔离网文件导出,是企业急需解决的一个难题。先来看一下,企业通常会采取哪些隔离方式吧?1、网闸/光闸隔离:阻断网络通信协议,......
  • git修改文件提交
    1,检查当前状态,查看是否有未提交的更改gitstatus2,如果有未提交的更改,使用gitadd命令将修改的文件添加到暂存区gitadd<file>如果添加所有修改的文件,可以使用gitadd.3,提交这些更改到你的本地仓库gitcommit-m“此处是提交的备注”4,如果已经做了一些更改并且想要查......
  • 如何简化不同网间文件摆渡的操作流程,降低IT人员工作量?
    为了保护内部核心数据不被泄露,同时有效屏蔽外部网络攻击的风险,企业大多会选择实施网络隔离。将“自己人”与“外人”隔离,具有较强的安全敏感性。有些企业还会在内部网络中进一步划分,比如划分为研发网、办公网、生产网等,但企业仍存在大量数据交互、文件摆渡的使用需求。网络隔离......