广告位联系
返回顶部
分享到

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

Golang 来源:互联网 作者:佚名 发布时间:2025-01-11 22:04:22 人浏览
摘要

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

协程与通道

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

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

1

channelName:= make(chan Type, n)

举例:

1

dataStream := make(chan string, 1)

往通道写数据:

1

dataStream <- "data"

从通道读数据:

1

varName := <-dataStream

关闭通道:

1

close(dataStream)

Go 超时机制

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

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,包括执行命令的所有参数,为字符串类型数组。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

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

}

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

1

2

3

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()方法检查读取文件过程中的错误。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

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()

}

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

1

2

go run main.go test.txt 0.1

# Program execution out of time

按块方式读文件

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

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

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超时机制是必要的,它有助于终止这种冗长的程序。本文通过示例展示了不同方式读取文件的超时机制实现。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 :
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计