Golang实现超时机制读取文件的方法示例

 更新时间:2025年01月10日 10:55:15   作者:梦想画家  
读写文件是Go程序的基本任务,包括使用程序查看文件内容、创建或修改文件,Go提供了os,ioutil,io以及bufio包实现文件操作,本文介绍如果在读文件过程中增加超时机制,避免文件太大一直占用资源,需要的朋友可以参考下

协程与通道

协程(Goroutine)是轻量级线程,可实现函数或方法与主程序流并行执行。使用go关键字:go func(){}。通道是协程直接的通讯管道,主要用于在协程间传输数据,即往通道写数据、从通道读数据。

通过chan关键字声明通道,可以使用var或:=两种方式声明,也可以声明待缓存的通道,语法如下:

channelName:= make(chan Type, n)

举例:

dataStream := make(chan string, 1)

往通道写数据:

dataStream <- "data"

从通道读数据:

varName := <-dataStream

关闭通道:

close(dataStream)

Go 超时机制

超时对于连接到外部资源或需要限制执行时间的场景来说非常重要。这是因为太长的服务器端处理将消耗太多的资源,导致并发性下降,甚至服务不可用。

利用select语句及并行协程实现超时,必须导入time包。然后使用time.After()参数创建通道,调用time.After(1 * time.Second)将在1秒后填充通道。下面示例通过通道和select实现超时:

package main
import (
    "fmt"
    "time"
)
func main() {
    dataChannel:= make(chan string, 1)

    go func() {
        time.Sleep(2 * time.Second)
        dataChannel <- "result 1"
    }()

    select {
        case results := <- dataChannel:
            fmt.Println(results)
        case <-time.After(1 * time.Second):
            fmt.Println("timeout 1")
    }
}

首先创建缓存通道dataChannel,调用函数模拟复杂业务,2秒后从非阻塞通道返回结果。select语句实现超时。results := <- dataChannel等待结果,time.After(1 * time.Second)语句1秒后返回值,因此select首先等待1秒,超过1秒将超时。

下面利用该机制实现读取文件超时机制实现。

读取整个文件

Go中读整个文件一般使用ioutil/os包中的Read File()函数,读取整个文件值字节slice。ioutil包最好别用于读取大文件,对于小文件完全够用。

os包包含执行参数数组Args,包括执行命令的所有参数,为字符串类型数组。

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"strconv"
	"time"
)

func main() {

	filePath := os.Args[1]
	timeOut, _ := strconv.ParseFloat(os.Args[2], 64)

	// buffered channel of dataStream
	dataStream := make(chan string, 1)
	// Run ReadFileToString function in it's own goroutine and pass back it's
	// response into dataStream channel.
	go func() {
		data, _ := ReadFileToString(filePath)
		dataStream <- data
		close(dataStream)
	}()

	// Listen on dataStream channel AND a timeout channel - which ever happens first.
	select {
	case res := <-dataStream:
		fmt.Println(res)
	case <-time.After(time.Duration(timeOut) * time.Second):
		fmt.Println("Program execution out of time ")
	}
}
func ReadFileToString(file string) (string, error) {
	content, err := ioutil.ReadFile(file)
	// error encountered during reading the data
	if err != nil {
		return "", err
	}
	// convert bytes to string
	return string(content), nil
}

我们可以使用不同的超时时间进行测试:

go run main.go text.txt 1.0

go run main.go text.txt 0.9

按行读文件

可以使用 bufio.Scanner 按行读文件,使用bufio.NewScanner(file)构造函数创建Scanner,然后通过Scan()和Text()方法逐行读取内容。使用Err()方法检查读取文件过程中的错误。

package main

import (
	"bufio"
	"fmt"
	"log"
	"os"
	"strconv"
	"time"
)

func main() {
	//get filepath and timeout on the terminal
	filePath := os.Args[1]
	timeOut, _ := strconv.ParseFloat(os.Args[2], 64)
	//creating  channels
	dataStream := make(chan string, 1)
	readerr := make(chan error)

	// Run ReadFileLineByLine function in its own goroutine and pass back it's
	// response into dataStream channel.
	go ReadFileLineByLine(filePath, dataStream, readerr)

loop:
	for {
		// select statement will block this thread until one of the three conditions below is met

		select {
		case data := <-dataStream:
			// Process each line
			fmt.Println(data)
		case <-time.After(time.Duration(timeOut) * time.Second):
			fmt.Println("Program execution out of time ")
			break loop
		case err := <-readerr:
			if err != nil {
				log.Fatal(err)
			}
			break loop
		}
	}
}

func ReadFileLineByLine(filePath string, data chan string, er chan error) {
	// open file
	file, err := os.Open(filePath)
	if err != nil {
		fmt.Println(err)
	}
	// close the file at the end of the program
	defer file.Close()

	// read the file line by line using scanner
	scanner := bufio.NewScanner(file)

	for scanner.Scan() {
		data <- scanner.Text()
	}
	close(data) // close causes the range on the channel to break out of the loop
	er <- scanner.Err()
}

当然也可以使用不同超时时间进行测试,如超时场景:

go run main.go test.txt 0.1
# Program execution out of time

按块方式读文件

对于非常大的文件使用块方式读取非常有用,无需把整个文件加载到内存中,每次读取固定块大小内容。下面readFileChunk函数中需要创建缓冲区,每次读取该缓冲区大小的内容,直到io.EOF错误出现,表明已经到达文件结尾。

缓冲区大小、目标文件以及超时时间作为函数参数,其他逻辑与上面示例一致:

package main

import (
   "fmt"
   "io"
   "log"
   "os"
   "strconv"
   "time"
)

func main() {
   dataStream := make(chan string, 1)
   filePath := os.Args[1]
   timeOut, _ := strconv.ParseFloat(os.Args[2], 64)
   chunkSize, _ := strconv.Atoi(os.Args[3])
   go readFileChunk (filePath, dataStream, int64(chunkSize))
   select {
   case resultData := <- dataStream:
      fmt.Println(resultData)
   case <-time.After(time.Duration(timeOut) * time.Millisecond):
      fmt.Println("timeout")
   }

}

func readFileChunk(filePath string, data chan string, chunkSize int64) {
   // open file
   f, err := os.Open(filePath)
   if err != nil {
      log.Fatal(err)
   }
   // remember to close the file at the end of the program
   defer f.Close()

   buf := make([]byte, chunkSize)
   for {
      readTotal, err := f.Read(buf)
      if err != nil && err != io.EOF {
         log.Fatal(err)
      }

      if err == io.EOF {
         break
      }

      data <- string(buf[:readTotal])
   }
   close(data)
}

总结

对于资源密集型程序正在执行时,Golang超时机制是必要的,它有助于终止这种冗长的程序。本文通过示例展示了不同方式读取文件的超时机制实现。

到此这篇关于Golang实现超时机制读取文件的方法示例的文章就介绍到这了,更多相关Golang超时机制读取文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang使用embed引入静态文件的实例代码

    Golang使用embed引入静态文件的实例代码

    Golang embed是Go 1.16版本中引入的一项新功能,它可以使嵌入文件更容易,通常,在Go中嵌入文件需要使用文件系统或者第三方包,而使用embed可以更加便捷地嵌入文件,从而方便地访问文件的内容,本文介绍了Golang使用embed引入静态文件,需要的朋友可以参考下
    2024-06-06
  • 在Go中编写测试代码的方法总结

    在Go中编写测试代码的方法总结

    在程序开发过程中,测试是非常重要的一环,甚至有一种开发模式叫 TDD,先编写测试,再编写功能代码,通过测试来推动整个开发的进行,可见测试在开发中的重要程度,为此,Go提供了testing框架来方便我们编写测试,本文将向大家介绍在Go中如何编写测试代码
    2023-07-07
  • 使用go语言实现Redis持久化的示例代码

    使用go语言实现Redis持久化的示例代码

    redis 是一个内存数据库,如果你把进程杀掉,那么里面存储的数据都会消失,那么这篇文章就是来解决 redis 持久化的问题,本文给大家介绍了使用go语言实现Redis持久化,需要的朋友可以参考下
    2024-07-07
  • go-micro微服务domain层开发示例详解

    go-micro微服务domain层开发示例详解

    这篇文章主要为大家介绍了go-micro微服务domain层开发示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • go特性之数组与切片的问题

    go特性之数组与切片的问题

    这篇文章主要介绍了go特性之数组与切片的问题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Go语言基础闭包的原理分析示例详解

    Go语言基础闭包的原理分析示例详解

    这篇文章主要为大家介绍了Go语言基础闭包的底层原理及实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2021-11-11
  • Go语言为什么不支持三元运算符原理解析

    Go语言为什么不支持三元运算符原理解析

    这篇文章主要为大家介绍了Go语言为什么不支持三元运算符原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Golang 并发读写锁的具体实现

    Golang 并发读写锁的具体实现

    Go语言中的sync.RWMutex提供了读写锁机制,允许多个协程并发读取共享资源,但在写操作时保持独占性,本文主要介绍了Golang 并发读写锁的具体实现,感兴趣的可以了解一下
    2025-02-02
  • Go Comparable Type原理深入解析

    Go Comparable Type原理深入解析

    这篇文章主要为大家介绍了Go Comparable Type原理深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • golang中http请求的context传递到异步任务的坑及解决

    golang中http请求的context传递到异步任务的坑及解决

    这篇文章主要介绍了golang中http请求的context传递到异步任务的坑及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03

最新评论