golang逐行读取文件的操作
来源:脚本之家
时间:2022-12-23 09:51:20 445浏览 收藏
IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《golang逐行读取文件的操作》,聊聊文件、读取,我们一起来看看吧!
我就废话不多说了,大家还是直接看代码吧~
func ReadLine(fileName string) ([]string,error){ f, err := os.Open(fileName) if err != nil { return nil,err } buf := bufio.NewReader(f) var result []string for { line, err := buf.ReadString('\n') line = strings.TrimSpace(line) if err != nil { if err == io.EOF { //读取结束,会报EOF return result,nil } return nil,err } result = append(result,line) } return result,nil }
补充:Golang读取文件和处理超大文件方案
Golang 操作文件的读取的方法很多,适用的场景也是各不相同,在此我们将文件的读取分为如下几种 :
文件整体读取
文件分片读取(块级读取)
文件行级读取
系统的配置不同,执行的耗时也不相同,此处给出一参考
系统配置 :
OS : Windows10
Memory : 16G
CPU (英特尔)Intel® Core™ i3-4370 CPU @ 3.80GHz(3800 MHz)
1. 文件整体读取
文件整体读取就是将文件一次性读取到,理解上是将文件的内容第一次就读取完了
使用场景 :
针对小文件比较合适(大文件读取空间和时间的消耗也很大)
对于整体性强的文件也比较合适(文件也不能太大)
代码示例1
package main import ( "bufio" "fmt" "io" "io/ioutil" "log" "os" "time" ) // 测试用的文本文件11M大小 var m11 string = `G:\runtime\log\ccapi\11M.log` // 测试用的文本文件400M大小 var m400 string = `G:\runtime\log\ccapi\400M.log` // 将整个文件都读取 func readAll(filePath string) { start1 := time.Now() ioutil.ReadFile(filePath) fmt.Println("readAll spend : ", time.Now().Sub(start1)) } func main() { readAll(m11) readAll(m400) }
$ go run main.go readAll spend : 6.9999ms readAll spend : 358.8014ms
代码示例2
package main import ( "bufio" "fmt" "io" "io/ioutil" "log" "os" "time" ) // 测试用的文本文件11M大小 var m11 string = `G:\runtime\log\ccapi\11M.log` // 测试用的文本文件400M大小 var m400 string = `G:\runtime\log\ccapi\400M.log` // 将文件完整读取 func readAllBuff(filePath string) { start1 := time.Now() // 打开文件 FileHandle, err := os.Open(filePath) if err != nil { log.Println(err) return } // 关闭文件 defer FileHandle.Close() // 获取文件当前信息 fileInfo, err := FileHandle.Stat() if err != nil { log.Println(err) return } buffer := make([]byte, fileInfo.Size()) // 读取文件内容,并写入buffer中 n, err := FileHandle.Read(buffer) if err != nil { log.Println(err) } // 打印所有切片中的内容 fmt.Println(string(buffer[:n])) fmt.Println("readAllBuff spend : ", time.Now().Sub(start1)) } func main() { readAllBuff(m11) readAllBuff(m400) }
2. 文件分片读取
对文件一部分一部分逐步的读取,直到文件完全读取完
PS : 每次读取文件的大小是根据设置的 分片 大小 ,所以对于读取文本类型的文件时(例如 : 日志文件)
不一定是按照你的期望逐行输出,因为不会处理文本尾部的换行符,而是按照分片大小读取内容
使用场景 :
读取超大的文件很合适
读二进制类型的文件很合适(比如:音视频文件或者资源类型文件等)
代码示例
package main import ( "bufio" "fmt" "io" "io/ioutil" "log" "os" "time" ) // 测试用的文本文件11M大小 var m11 string = `G:\runtime\log\ccapi\11M.log` // 测试用的文本文件400M大小 var m400 string = `G:\runtime\log\ccapi\400M.log` // 文件一块一块的读取 func readBlock(filePath string) { start1 := time.Now() FileHandle, err := os.Open(filePath) if err != nil { log.Println(err) return } defer FileHandle.Close() // 设置每次读取字节数 buffer := make([]byte, 1024) for { n, err := FileHandle.Read(buffer) // 控制条件,根据实际调整 if err != nil && err != io.EOF { log.Println(err) } if n == 0 { break } // 如下代码打印出每次读取的文件块(字节数) //fmt.Println(string(buffer[:n])) } fmt.Println("readBolck spend : ", time.Now().Sub(start1)) } func main() { readBlock(m11) readBlock(m400) }
$ go run main.go readBolck spend : 31.9814ms readBolck spend : 1.0889488s
3. 文件逐行读取
对文件一行一行的读取,直到读到文件末尾
使用场景 :
读取超大的文件很合适(例如 : 超大log文件等)
读取的文件最好是有换行的(如果使用单行文件组成的大文件,需要注意)
对需要分析内容的大文件
统计某些数据出现的次数
查询某些数据是否存在
查找指定行的数据
示例代码1
package main import ( "bufio" "fmt" "io" "io/ioutil" "log" "os" "time" ) // 测试用的文本文件11M大小 var m11 string = `G:\runtime\log\ccapi\11M.log` // 测试用的文本文件400M大小 var m400 string = `G:\runtime\log\ccapi\400M.log` // 读取文件的每一行 func readEachLineReader(filePath string) { start1 := time.Now() FileHandle, err := os.Open(filePath) if err != nil { log.Println(err) return } defer FileHandle.Close() lineReader := bufio.NewReader(FileHandle) for { // 相同使用场景下可以采用的方法 // func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) // func (b *Reader) ReadBytes(delim byte) (line []byte, err error) // func (b *Reader) ReadString(delim byte) (line string, err error) line, _, err := lineReader.ReadLine() if err == io.EOF { break } // 如下是某些业务逻辑操作 // 如下代码打印每次读取的文件行内容 fmt.Println(string(line)) } fmt.Println("readEachLineReader spend : ", time.Now().Sub(start1)) } func main(){ readEachLineReader(m11) readEachLineReader(m400) }
$ go run main.go readEachLineReader spend : 16.9902ms readEachLineReader spend : 537.9683ms
代码示例2
package main import ( "bufio" "fmt" "io" "io/ioutil" "log" "os" "time" ) // 测试用的文本文件11M大小 var m11 string = `G:\runtime\log\ccapi\11M.log` // 测试用的文本文件400M大小 var m400 string = `G:\runtime\log\ccapi\400M.log` // 读取文件的每一行 func readEachLineScanner(filePath string) { start1 := time.Now() FileHandle, err := os.Open(filePath) if err != nil { log.Println(err) return } defer FileHandle.Close() lineScanner := bufio.NewScanner(FileHandle) for lineScanner.Scan() { // 相同使用场景下可以使用如下方法 // func (s *Scanner) Bytes() []byte // func (s *Scanner) Text() string // 实际逻辑 : 对读取的内容进行某些业务操作 // 如下代码打印每次读取的文件行内容 fmt.Println(lineScanner.Text()) } fmt.Println("readEachLineScanner spend : ", time.Now().Sub(start1)) } func main() { readEachLineScanner(m11) readEachLineScanner(m400) }
$ go run main.go readEachLineScanner spend : 17.9895ms readEachLineScanner spend : 574.1722ms
4. 总结
面试中常见的类似超大文件读取的问题,通常我们采用分片读取或者逐行读取的方案即可
大文件的上传也可以采用类似的解决方案 , 每次读取文件的部分内容上传(写入)网络接口中,直至文件读取完毕
普通的小文件并且对内容没有太多操作的,可以采用整体读取,速度相对较快
对文件内容有操作的采用分片读取和逐行读取更合适
二进制类型文件采用分片读取或者整体读取的方案比较合适
文件读取不仅是本地文件,要读去网络上的文件(各种文档,音视频,图片,和其他各种类型文件)时要访问到文件获取 io.ReadCloser 或者 io.Reader 后可以采用三种方式将文件内容读取到
func ReadAll(r io.Reader) ([]byte, error) 文件完整读取
func Copy(dst Writer, src Reader) (written int64, err error) 文件读取并写入
type Reader interface { Read(p []byte) (n int, err error) }
通过Reader 接口的 Read 方法读取
以上为个人经验,希望能给大家一个参考,也希望大家多多支持golang学习网。如有错误或未考虑完全的地方,望不吝赐教。
好了,本文到此结束,带大家了解了《golang逐行读取文件的操作》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!
-
400 收藏
-
235 收藏
-
359 收藏
-
426 收藏
-
495 收藏
-
419 收藏
-
234 收藏
-
155 收藏
-
457 收藏
-
309 收藏
-
225 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 善良的台灯
- 这篇技术贴出现的刚刚好,太细致了,很有用,已收藏,关注师傅了!希望师傅能多写Golang相关的文章。
- 2023-02-26 07:15:37
-
- 大意的烤鸡
- 细节满满,已收藏,感谢作者的这篇文章内容,我会继续支持!
- 2023-02-14 04:54:23
-
- 聪明的朋友
- 赞 👍👍,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢up主分享技术文章!
- 2023-02-13 00:31:22
-
- 玩命的砖头
- 这篇文章内容太及时了,细节满满,真优秀,已加入收藏夹了,关注楼主了!希望楼主能多写Golang相关的文章。
- 2023-01-25 19:36:41