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 方法读取

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • golang 如何获取pem格式RSA公私钥长度

    因在做license注册机制当中,有对根据本地RSA pem密钥文件判断出RSA的公私密钥长度的需求(即:根据pem内容判断出RSA密钥是1024位或者2048位,或者其他位数等),因此个人通过思考,摸索整理出一个方法,予以记录,备用,分享. package main import ( "crypto/rsa" "crypto/x509" "encoding/pem" "errors" "fmt" &quo

  • golang 字符串切片去重实例

    实现目的:实现字符串切片去重,只是两个字符完全相同时,去除一个. 实现方式:考虑两种,一种是常规的双重循环去除,另一种是利用map的key的唯一性实现. 1.通过双重循环来过滤重复元素 方法1, 思路:利用for双重循环,新建一个slice,遍历原slice中的每一个元素,每一次判断这个元素和后面元素是否相同,若相同则去除,若不同则存入新slice中,判断本元素后,再继续判断下一个元素,直到判断完毕. package main import "fmt" func main() { va

  • golang 64位linux环境下编译出32位程序操作

    目标:在64位linux系统上编译出32位程序. 操作: 1.执行 go env 查看当前go环境配置 2.执行 export GOARCH=386 配置go输出系统平台为32位 3.go build 编译程序 4.使用file main 指令查看编译出的可执行程序是否为32位 实践图片: 补充:golang float32/64与[]byte互转 网络协议开发中经常需要将int.float.bool等转为二进制数据,float32.64 与[]byte处理: import ( "encodin

  • Golang中的path/filepath包用法

    path/filepath包下的相关函数 1. ToSlash函数 func ToSlash(path string) string 功能:将path中平台相关的路径分隔符转换成'/' 例如:windows当前路径: D:\gopro\src\study,转换之后D:/gopro/src/study 2. FromSlash函数 func FromSlash(path string) string 功能:将 path 中的 '/' 转换为系统相关的路径分隔符 3.Dir函数 func Dir(p

  • 以alpine作为基础镜像构建Golang可执行程序操作

    Alpine介绍 Alpine 操作系统是一个面向安全的轻型 Linux 发行版.它不同于通常 Linux 发行版,Alpine 采用了 musl libc 和 busybox 以减小系统的体积和运行时资源消耗,但功能上比 busybox 又完善的多,因此得到开源社区越来越多的青睐.在保持瘦身的同时,Alpine 还提供了自己的包管理工具 apk,可以通过 https://pkgs.alpinelinux.org/packages 网站上查询包信息,也可以直接通过 apk 命令直接查询和安装各种

  • golang 解析word文档操作

    baliance/gooxml gooxml是可以对整个office document提供支持的golang库,功能很强大,这里简单给出对word文档的读取案例 安装 go get baliance.com/gooxml/ go build -i baliance.com/gooxml/- 解析word代码 package main import ( "fmt" "log" "baliance.com/gooxml/document" ) fun

  • golang-redis之sorted set类型操作详解

    1:安装redigo go get github.com/garyburd/redigo/redis 2:引用redigo import ( "github.com/garyburd/redigo/redis" ) 3:连接Redis c, err := redis.Dial("tcp", "192.168.2.225:6379") if err != nil { fmt.Println("connect to redis err&qu

  • 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

  • Golang并发读取文件数据并写入数据库的项目实践

    目录 需求 项目结构 获取data目录下的文件 按行读取文本数据 数据类型定义 并发读取文件 将数据写入数据库 完整main.go代码 测试运行 需求 最近接到一个任务,要把一批文件中的十几万条JSON格式数据写入到Oracle数据库中,Oracle是企业级别的数据库向来以高性能著称,所以尽可能地利用这一特性.当时第一时间想到的就是用多线程并发读文件并操作数据库,而Golang是为并发而生的,用Golang进行并发编程非常方便,因此这里选用Golang并发读取文件并用Gorm操作数据库.然而Go

  • python使用fileinput模块实现逐行读取文件的方法

    本文实例讲述了python使用fileinput模块实现逐行读取文件的方法.分享给大家供大家参考.具体实现方法如下: #-------------------------------- # Name: read_lines.py # Author: Kevin Harris # Last Modified: 02/13/04 # Description: This Python script demonstrates # how to use fileinput to read # each l

  • node.js实现逐行读取文件内容的代码

    在此之前先介绍一个逐行读取文件内容NPM:https://github.com/nickewing/line-reader,需要的朋友可以看看. 直接上代码: function readLines(input, func) { var remaining = ''; input.on('data', function(data) { remaining += data; var index = remaining.indexOf('\n'); while (index > -1) { var l

  • C#逐行读取文件的方法

    本文实例讲述了C#逐行读取文件的方法.分享给大家供大家参考.具体如下: 这里使用C#逐行读取文件,对于大文件的读取非常有用. StreamReader sr = new StreamReader("fileName.txt"); string line; while((line= sr.ReadLine()) != null) { Console.WriteLine("xml template:"+line); } if (sr != null)sr.Close()

  • PHP检查文件是否存在,不存在自动创建及读取文件内容操作示例

    本文实例讲述了PHP检查文件是否存在,不存在自动创建及读取文件内容操作.分享给大家供大家参考,具体如下: <?php $filename = 'a/b.html'; $writetext = 'ssssssssssss'; $result = jwritefile($filename, $writetext); var_dump($result);die; function jwritefile($filename, $writetext) { $position = strrpos($file

  • Python逐行读取文件内容的方法总结

    Python四种逐行读取文件内容的方法 下面四种Python逐行读取文件内容的方法, 分析了各种方法的优缺点及应用场景,以下代码在python3中测试通过, python2中运行部分代码已注释,稍加修改即可. 方法一:readline函数 # -*- coding: UTF-8 -*- f = open("/pythontab/code.txt") # 返回一个文件对象 line = f.readline() # 调用文件的 readline()方法 while line: # pri

  • Python3读取文件的操作详解

    目录 1.引言 2. fileinput 2.1 方法介绍 2.2 默认读取 2.3 处理一个文件 2.4 处理批量文件 2.5 读取与备份 2.5 重定向替换 2.6 进阶 3.总结 1.引言 小鱼:小屌丝, 这段代码为什么要开两个线程? 小屌丝:因为我要读写文件,还要备份文件,所以就开两个线程了. 小鱼:嗯,想法是对的,但是,还有一种简便的方法, 不需要开两个线程就能搞得定的. 小屌丝:额…难道是with open? 小鱼:不是. 小屌丝:那还有啥呢? 我咋想不起来了. 小鱼:嗯,这个方法很

  • node.js readline和line-reader逐行读取文件方法

    逐行读取文件的能力允许我们读取大文件,而无需将其全部存储到内存中.它有助于节省资源和提高应用程序的效率. 它允许我们寻找所需的信息,一旦找到了相关的信息,我们可以停止搜索过程,可以防止不必要的内存使用. 我们将使用Readline模块和Line-Reader模块来实现这一目标. 方法一 readline 使用Readline模块:Readline是Node的原生模块.它是专门为从任何可读流逐行读取内容而开发的.它可用于从命令行读取数据. 因为模块是Node的本机模块.js,它不需要任何安装,可以

  • Shell逐行读取文件的4种方法

    在Linux中有很多方法逐行读取一个文件的方法,其中最常用的就是下面的脚本里的方法,而且是效率最高,使用最多的方法.为了给大家一个直观的感受,我们将通过生成一个大的文件的方式来检验各种方法的执行效率. 方法1:while循环中执行效率最高,最常用的方法. 复制代码 代码如下: function while_read_LINE_bottm(){ While read LINE do echo $LINE done  < $FILENAME } 注释:我习惯把这种方式叫做read釜底抽薪,因为这种方

随机推荐