Golang 实现分片读取http超大文件流和并发控制

分片读取http超大文件流

Golang中的HTTP发送get请求,在获取内容有两种情况。

Golang发送http get请求方式

resp, err := http.Get(sendUrl)
if err != nil {
 fmt.Println("出错", err)
 return
}

第一种方式是直接全部读取出来,这种方式在小数据量的时候很方便。

body变量直接全部接收resp响应内容

body, err2 := ioutil.ReadAll(resp.Body)

第二种方式,分片获取。

首先顶一个切片buf := make([]byte, 4096) 容量和大小都是4096个char字符(切片就是Golang自己的动态变长数组)

for无限循环读取,读取一块内容放入buf中。result 是一个string字符串,然后用 result 自动拼接。

for {
  n, err:= resp.Body.Read(buf)
 if err != nil || n == 0{
 fmt.Println("出现错误")
 break
 }
 result += string(buf[:n])
}

Golang中匹配正则

MustCompile内容不是单引号,而是 `

// 解析,编译正则表达式
ret := regexp.MustCompile(`<img width="100" alt="(?:(.*?))"`)
//提取需要信息
var fileName [][] string = ret.FindAllStringSubmatch(result, -1)

该方法可以进一步推广,可以推广到下载超大文件,然后分片读取和写入硬盘。

然后再开启另一个线程去将这些已经写入硬盘的分片合称在一起。

Golang 并发控制

Java中的多线程,如果主线程开启多个子线程后,在多个子线程全部完成后,主线程才会退出,程序终止。

而在Golang中不会出现此类情况,主Go程和子Go程需要人为控制主GO程和子GO程同步,否则主GO程瞬间结束。

在主GO程开始执行子GO程地方创建一个 channel。子GO程开始往 channel 中添加数据,主GO程再消费数据。

func toWork(start, end int) {
 //子Go程与主Go程完成同步,意思是子Go程没有全部执行完毕,主Go程不许退出。
 page := make(chan int) 

 for i:=start; i<=end; i++ {
 //开启子GO程
 go SpiderPage(i, page)
 }
 //主GO程开始消费管道中的数据
 for i:=start; i<=end; i++ {
 fmt.Println("爬取完成", <- page)
 }
}

往主GO程的channel中添加数据,提供给主GO程消费从而达到同步

func SpiderPage(index int, page chan int) {
 page <- index
}

读取http二进制码写入图片

创建文件

获取http流

分片逐步写入

func saveImag(sendUrl string, index int, imageChannel chan int) {
 //创建文件
 path := "C:/img/" + strconv.Itoa(index) + ".jpg"
 f, err := os.Create(path)
 if err != nil {
 return
 }
 defer f.Close()
 //获取http流
 resp, err :=http.Get(sendUrl)
 if err != nil {
 return
 }
 defer resp.Body.Close()
 //分片逐步写入
 buf := make([]byte, 4096)
 for {
 n, err := resp.Body.Read(buf)
 if err != nil {
  break
 }
 f.Write(buf[:n])
 }
 imageChannel <- index
}

补充:golang实现http表单大文件流式上传服务端代码

golang的http标准库的上传文件是一次性将文件全部读到内存中,这样上传小文件还可以,但是大文件就无能为力了。

一开始在网上找到一篇gin实现大文件流式上传的文章。大体思路是手动解析form表单的header和body,然后分片读取上传的文件内容。但是代码量有点多且复杂。有兴趣的同学可以自行百度。

后来在github找到一个库

github.com/albrow/forms

可以看到这个库读取上传文件的方法

func (d Data) GetFileBytes(key string) ([]byte, error) {
 fileHeader, found := d.Files[key]
 if !found {
 return nil, nil
 } else {
 file, err := fileHeader.Open()
 if err != nil {
  return nil, err
 }
 return ioutil.ReadAll(file)
 }
}

最后使用的是ioutil.ReadAll,大文件上传的话就会有问题,要实现流式上传,可以在这个包里加一个方法。以下是我自己加的方法

func (d Data) GetFileReader(key string) (io.Reader, error) {
 fileHeader, found := d.Files[key]
 if !found {
 return nil, nil
 } else {
 file, err := fileHeader.Open()
 if err != nil {
  return nil, err
 }
 return file, nil
 }
}

得到reader后使用io.Copy即可将文件落盘

 userData, err := forms.Parse(c.Request)
  if err != nil {
  log.Printf("parse错误:%v", err)
  return
  }
  header := userData.GetFile("file")
  fileReader, err := userData.GetFileReader("file")
  if err != nil {
  log.Printf("获取reader错误:%v", err)
  return
  }
  file, _ := os.Create(header.Filename)
  io.Copy(file, fileReader)

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

(0)

相关推荐

  • golang http请求封装代码

    在GOPATH 中创建 utils 文件夹 放置这两个文件 http.go package utils import ( "crypto/tls" "encoding/json" "errors" "fmt" "io/ioutil" "net/http" "net/url" "strings" "sync" ) var ( GE

  • 解决golang http.FileServer 遇到的坑

    上次写了一个2行实现一个静态服务器的文章 今天群里有个哥们是这么写居然返回的是404 见鬼了嘛?? http.handle("/js", http.FileServer(http.Dir("js")) http.ListenAndServe("8080", nil) 大概的意思就是绑定 路由为 js 的时候访问这个js 文件夹 看了一下确实代码上面没什么毛病.但是路径怎么修改 也不好使. 我把代码拿到我的 电脑上面运行 shitfuck 这是搞什

  • 在Golang中使用http.FileServer返回静态文件的操作

    Golang中使用http.FileServer 使用http.FileServer可以管理向浏览器返回静态文件 http.Handle("/",http.FileServer(http.Dir("/Users/administrator/Desktop/public"))) err := http.ListenAndServe("0.0.0.0:8080",nil) if err!=nil{ fmt.Print(err); } 补充:golan

  • 解决golang读取http的body时遇到的坑

    当服务端对http的body进行解析到map[string]interface{}时,会出现cli传递的是int类型,而服务端只能断言成float64,而不能将接收到的本该是int类型的直接断言为int cli func main(){ url:="http://127.0.0.1:8335/api/v2/submit" myReq:= struct { ProductId int `json:"product_id"` Mobile string `json:&q

  • 解决golang处理http response碰到的问题和需要注意的点

    在处理http response的时候,偶然发现,body读取之后想再次读取的时候,发现读不到任何东西. 见下方代码: response, err = ioutil.ReadAll(resp.Body) if err != nil { log.Println("ioutil ReadAll failed :", err.Error()) return } 之后如果想再次ioutil.ReadAll(resp.Body)的时候会发现读到的是空.于是我决定去看一下这个resp.Body,发

  • golang HTTP 服务器 处理 日志/Stream流的操作

    目前,我开发 HTTP 服务, 用的是 beego框架, 方便了很多. 但是, 有时候,还是会遇到一些 特殊的场景. 比如: 过滤日志. 这应该是一种典型的stream,同时数据量也适中, 不会有人,为了这个, 就用一些很重的框架. 可以这样直观的描述这个 逻辑 其他组件 产生 log || \ / 我的组件,业务处理 || \ / 用户, http client 这种情景下, 有几个特殊点: 1. 难以用 string,或者 byte 数组 收集数据 2. 数据Source 端,不断的有数据产

  • Golang 实现分片读取http超大文件流和并发控制

    分片读取http超大文件流 Golang中的HTTP发送get请求,在获取内容有两种情况. Golang发送http get请求方式 resp, err := http.Get(sendUrl) if err != nil { fmt.Println("出错", err) return } 第一种方式是直接全部读取出来,这种方式在小数据量的时候很方便. body变量直接全部接收resp响应内容 body, err2 := ioutil.ReadAll(resp.Body) 第二种方式,

  • Java加速读取复制超大文件

    用文件通道(FileChannel)来实现文件复制,供大家参考,具体内容如下 不考虑多线程优化,单线程文件复制最快的方法是(文件越大该方法越有优势,一般比常用方法快30+%): 直接上代码: package test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io

  • HttpsURLConnection上传文件流(实例讲解)

    项目需要对接外部接口,将图片文件流发送到外部接口,下面代码就是HttpsURLConnection如何上传文件流: /** * HttpsURLConnection上传文件流 * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { //本地图片 java.io.File file = new java.io.File("/Users/jikukalun/Pic

  • Golang 实现超大文件读取的两种方法

    Golang超大文件读取的两个方案 流处理方式 分片处理 去年的面试中我被问到超大文件你怎么处理,这个问题确实当时没多想,回来之后仔细研究和讨论了下这个问题,对大文件读取做了一个分析 比如我们有一个log文件,运行了几年,有100G之大.按照我们之前的操作可能代码会这样写: func ReadFile(filePath string) []byte{ content, err := ioutil.ReadFile(filePath) if err != nil { log.Println("Re

  • 如何使用Golang创建与读取Excel文件

    目录 摘要 引言 正文 架构 文件对象 数据的表示 数据的解析 实际架构 Excelize 基础库 文件 坐标 样式 单元格操作 数据验证 数据的表示和解析 表示 解析 大规模数据的写入 需要关注的问题 大量枚举值的设置 大工作表的读取 流式写入的注意事项 结语 参考资料 总结 摘要 本文提出一种使用 Golang 进行 Excel 文件创建和读取的方案.首先对问题进行分析,引出方案的基本架构:然后分章节描述了 Excelize 基础库的基本用法,以及 Excel 数据在 Golang 中的表示

  • Python多进程分块读取超大文件的方法

    本文实例讲述了Python多进程分块读取超大文件的方法.分享给大家供大家参考,具体如下: 读取超大的文本文件,使用多进程分块读取,将每一块单独输出成文件 # -*- coding: GBK -*- import urlparse import datetime import os from multiprocessing import Process,Queue,Array,RLock """ 多进程分块读取文件 """ WORKERS = 4

  • android从资源文件中读取文件流并显示的方法

    本文实例讲述了android从资源文件中读取文件流并显示的方法.分享给大家供大家参考.具体如下: 在android中,假如有的文本文件,比如TXT放在raw下,要直接读取出来,放到屏幕中显示,可以这样: private void doRaw(){ InputStream is = this.getResources().openRawResource(R.raw.ziliao); try{ doRead(is); }catch(IOException e){ e.printStackTrace(

  • PHP快速按行读取CSV大文件的封装类分享(也适用于其它超大文本文件)

    CSV大文件的读取已经在前面讲述过了(PHP按行读取.处理较大CSV文件的代码实例),但是如何快速完整的操作大文件仍然还存在一些问题. 1.如何快速获取CSV大文件的总行数? 办法一:直接获取文件内容,使用换行符进行拆分得出总行数,这种办法对小文件可行,处理大文件时不可行:办法二:使用fgets一行一行遍历,得出总行数,这种办法比办法一好一些,但大文件仍有超时的可能:办法三:借助SplFileObject类,直接将指针定位到文件末尾,通过SplFileObject::key方法获取总行数,这种办

  • 用PHP读取超大文件的实例代码

    去年年底的各种网站帐号信息的数据库泄漏,很是给力啊,趁机也下载了几个数据库,准备学学数据分析家来分析一下这些帐号信息.虽然这些数据信息都已经被"整理"过的,不过自己拿来学习也挺有用的,毕竟有这么大的数据量. 数据量大带来的问题就是单个文件很大,能够打开这个文件相当不容易,记事本就不要指望了,果断死机.用MSSQL的客户端也打不开这么大的SQL文件,直接报内存不足,原因据说是MSSQL在读取数据的时候,是一次性地将读取到的数据放在内存中,如果数据量过大,而内存不足,则会直接导致系统瘫掉.

  • C#使用文件流读取文件的方法

    本文实例讲述了C#使用文件流读取文件的方法.分享给大家供大家参考.具体如下: using System; using System.IO; namespace Client.Chapter_11___File_and_Streams { public class OpenExistingFile { static void Main(string[] args) { FileInfo MyFile = new FileInfo(@"c:\Projects\Testing.txt");

随机推荐