go语言处理文件上传和多个文件上传

本文提供了一个使用Go语言实现的文件上传示例,包括单文件上传和多文件上传的功能。通过两个HTML页面和Go后端代码展示了如何接收并保存上传的文件。

uploadOne.html代码如下:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <form action="http://127.0.0.1:9090/uploadOne" method="post" enctype="multipart/form-data">
        文件:<input type="file" name="file" value="">
        <input type="submit" value="提交">
    </form>
</body>
</html>

uploadMore.html代码如下:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <form action="http://127.0.0.1:9090/uploadMore" method="post" enctype="multipart/form-data">
        文件:<input type="file" name="file" value=""><br>
        文件:<input type="file" name="file" value=""><br>
        文件:<input type="file" name="file" value=""><br>
        <input type="submit" value="提交">
    </form>
</body>
</html>

main.go代码如下:

package main

import (
	"net/http"
	"os"
	"io"
	"html/template"
	"log"
)

func uploadOne(w http.ResponseWriter, r *http.Request) {
	//判断请求方式
	if r.Method == "POST" {
		//设置内存大小
		r.ParseMultipartForm(32 << 20);
		//获取上传的第一个文件
		file, header, err := r.FormFile("file");
		defer file.Close();
		if err != nil {
			log.Fatal(err);
		}
		//创建上传目录
		os.Mkdir("./upload", os.ModePerm);
		//创建上传文件
		cur, err := os.Create("./upload/" + header.Filename);
		defer cur.Close();
		if err != nil {
			log.Fatal(err);
		}
		//把上传文件数据拷贝到我们新建的文件
		io.Copy(cur, file);
	} else {
		//解析模板文件
		t, _ := template.ParseFiles("./uploadOne.html");
		//输出文件数据
		t.Execute(w, nil);
	}
}

func uploadMore(w http.ResponseWriter, r *http.Request) {
	if r.Method == "POST" {
		//设置内存大小
		r.ParseMultipartForm(32 << 20);
		//获取上传的文件组
		files := r.MultipartForm.File["file"];
		len := len(files);
		for i := 0; i < len; i++ {
			//打开上传文件
			file, err := files[i].Open();
			defer file.Close();
			if err != nil {
				log.Fatal(err);
			}
			//创建上传目录
			os.Mkdir("./upload", os.ModePerm);
			//创建上传文件
			cur, err := os.Create("./upload/" + files[i].Filename);
			defer cur.Close();
			if err != nil {
				log.Fatal(err);
			}
			io.Copy(cur, file);
		}
	} else {
		//解析模板文件
		t, _ := template.ParseFiles("./uploadMore.html");
		//输出文件数据
		t.Execute(w, nil);
	}
}

func main() {
	http.HandleFunc("/uploadMore", uploadMore);
	http.HandleFunc("/uploadOne", uploadOne);
	err := http.ListenAndServe(":9090", nil);
	if err != nil {
		log.Fatal(err);
	}
}

通过http://127.0.0.1:9090/uploadOne和http://127.0.0.1:9090/upladMore来测试文件上传。

转载于:https://www.cnblogs.com/jkko123/p/7001673.html

基于go的大文件切片上传、断点续传、秒传.zip 1、如何唯一标示一个文件文件的信息后端会存储在mysql数据库表中。 在上传之前,前端通过 spark-md5.js 计算文件的md5值以此去唯一的标示一个文件。 spark-md5.js 地址:satazor/js-spark-md5 README.md中有spark-md5.js的使用demo,可以去看看。 2、断点续传是如何实现的? 断点续传可以实现这样的功能,比如RD上传200M的文件,当用户上传完199M时,断网了,有了断点续传的功能,我们允许RD再次上传时,能从第199M的位置重新上传。 实现原理: 实现断点续传的前提是,大文件切片上传。然后前端得问后端哪些chunk曾经上传过,让前端跳过这些上传过的chunk就好了。 前端的上传器(uploader.js)在上传时会先发送一个GET请求,这个请求不会携带任何chunk数据,作用就是向后端询问哪些chunk曾经上传过。 后端会将这些数据保存在mysql数据库表中。比如按这种格式:1:2:3:5表示,曾经上传过的分片有1,2,3,5。第四片没有被上传,前端会跳过1,2,3,5。 仅仅会将第四个chunk发送给后端。 3、秒传是如何实现的? 秒传实现的功能是:当RD重复上传一份相同的文件时,除了第一次上传会正常发送上传请求后,其他的上传都会跳过真正的上传,直接显示秒成功。 实现方式: 后端存储着当前文件的相关信息。为了实现秒传,我们需要搞一个字段(isUploaded)表示当前md5对应的文件是否曾经上传过。 后端在处理 前端的上传器(uploader.js)发送的第一个GET请求时,会将这个字段发送给前端,比如 isUploaded = true。前端看到这个信息后,直接跳过上传,显示上传成功。 4、上传暂停是如何实现的? 上传的暂停:并不是去暂停一个已经发送出去的正在进行数据传输的http请求~ 而是暂停发送起发送下一个http请求。 就我们的项目而言,因为我们的文件本来就是先切片,对于我们来说,暂停文件上传,本质上就是暂停发送下一个chunk。 5、前端上传并发数是多少? 前端的uploader.js中默认会三条线程启动并发上传,前端会在同一时刻并发 发送3个chunk,后端就会相应的为每个请求开启三个协程处理上传的过来的chunk。 在我们的项目中,会将前端并发数调整成了1。原因如下: 因为考虑到了断点续传的实现,后端需要记录下曾经上传过哪些切片。(这个记录在mysql的数据库表中,以 ”1:2:3:4:5“ )这种格式记录。 Mysql5.7默认的存储引擎是innoDB,默认的隔离级别是RR。如果我们将前端的并发数调大,就会出现下面的异常情况: 1. goroutine1 获取开启事物,读取当前上传到记录是 1:2 (未提交事物) 2. goroutine1 在现有的记录上加上自己处理的分片3,并现有的1:2拼接在一起成1:2:3 (未提交事物) 3. goroutine2 获取开启事物,(因为RR,所以它读不到1:2:3)读取当前上传到记录是 1:2 (未提交事物) 4. goroutine1 提交事物,将1:2:3写回到mysql 5. goroutine2 在现有的记录上加上自己处理的分片4,并现有的1:2拼接在一起成1:2:4 (提交事物) 可以看到,如果前端并发上传,后端就会出现分片丢失的问题。 故前端将并发数置为1。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值