踩坑日志:go并发读取文件

我的应用场景是:并发的读取一个文件(或者一个超大的文件),计算文件的hash值,
就比如:文件60G,你的内存4G,如何计算?
这个例子是不是不太可能实现:

func main() {
	ffff, err := os.Open("./2.txt")
	if err != nil {
		fmt.Println("读取文件失败!")
	}
	defer ffff.Close()

	hash := md5.New()
	if _, err := io.Copy(hash, ffff); err != nil {
		log.Fatal(err)
	}
	sum := hash.Sum(nil)

	fmt.Printf("%x\n", sum)
}

这是平常的方法,对于超大文件是肯定不合适的

好了 ,直接上代码,这是我做的,可能有点小瑕疵,待解决,大神们也可直接指点迷津~~~


import (
	"bufio"
	"bytes"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"io"
	"log"
	"os"
	"sync"
	"time"
)

// 多线程读取大文件 计算hash值

// 分片计算的结果
var dictResult sync.Map

// 是否已经读取结束
var fileEnd chan struct{}

// 并发控制
var dictThread chan struct{}

// 文件路径 
var filePath = "./2.txt"

// 分片读取大小
var readSize = 20

// 并发的线程数量
var threadNum = 3

func main() {
	dictThread = make(chan struct{}, threadNum)
	fileEnd = make(chan struct{})
	
	for i := 0; ; i++ {
		t := i
		dictThread <- struct{}{}
		go readFileByByte(filePath, t*readSize-1, i)
		select {
		case <-fileEnd:
			goto Next
		default:
		}

	}
Next:
	time.Sleep(time.Second)
	ret := make([]string, 0)
	for i := 0; ; i++ {
		value, ok := dictResult.LoadAndDelete(i)
		if !ok {
			break
		}
		ret = append(ret, value.(string))
	}

	r := md5.Sum([]byte(buildString(ret...)))

	fmt.Println(hex.EncodeToString(r[:]))
}

// 按字节读取文件: 文件路径,偏移量,第几片,
func readFileByByte(filePath string, set int, pageNum int) {

	f, err := os.Open(filePath)
	if err != nil {
		log.Fatal(err)
		return
	}

	if set == -1 {
		set = 0
	}
	_, err = f.Seek(int64(set), io.SeekStart)
	if err != nil {
		f.Close()
		fmt.Println(err.Error())
		fileEnd <- struct{}{} // 结束了
		return
	}

	var buf = make([]byte, 4096)
	reader := bufio.NewReader(f)
	n, err := reader.Read(buf)
	f.Close()
	<-dictThread
	if err != nil && err != io.EOF || n == 0 {
		fileEnd <- struct{}{} // 结束了
		return
	}
	// md5 计算
	sum := md5.Sum(buf[:n])
	dictResult.Store(pageNum, hex.EncodeToString(sum[:]))
	fmt.Println(pageNum, "==>>", hex.EncodeToString(sum[:]))
	return
}
func buildString(pieces ...string) string {
	var strBuf bytes.Buffer
	for _, piece := range pieces {
		strBuf.WriteString(piece)
	}
	return strBuf.String()
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值