断点续传(上传)C#版
1. 客户每次上传前先获取一下当前文件已经被服务器接受了多少
2. 上传时设定偏移量
服务端代码如下:
/// <summary>
/// 断点续传,获取已上传文件大小
/// </summary>
/// <returns></returns>
[HttpPost]
public long GetFileLength()
{
long result = 0;
FileStream fStream = null;
BinaryReader bReader = null;
try
{
var fileName = "";
IEnumerable<string> hasFileNameList = new List<string>();
bool hasFileName = Request.Headers.TryGetValues("FileName", out hasFileNameList);
if (hasFileName && hasFileNameList.Any())
{
fileName = hasFileNameList.First();
}
//设置文件存放路径
string dir = HttpContext.Current.Server.MapPath(@"~\UploadFiles");
fileName= dir+"\\"+fileName;
if (File.Exists(fileName))
{
FileInfo file = new FileInfo(fileName);
result = file.Length;
}
}
catch (Exception ex)
{
logger.Error(ex, ex.Message);
}
return result;
} /// <summary>
/// 断点续传 服务端保存文件代码
/// <param>Offset 偏移量</param>
/// </summary>
/// <returns></returns>
[HttpPost]
public Bussiness<bool> UploadFile()
{
#region Log Test
FileStream fStreamLog = null;
BinaryReader bReaderLog = null;
try
{
fStreamLog = new FileStream(SavePath + "\\" + $"{DateTime.Now:HHmmss}.File.tmp", FileMode.OpenOrCreate, FileAccess.ReadWrite);
int upLoadLengthTest = (int)HttpContext.Current.Request.InputStream.Length;
bReaderLog = new BinaryReader(HttpContext.Current.Request.InputStream);
byte[] dataTest = new byte[upLoadLengthTest];
bReaderLog.Read(dataTest, 0, upLoadLengthTest); //将上传文件流读到byte[]中
fStreamLog.Write(dataTest, 0, upLoadLengthTest); //将byte[]写到文件中,
}
catch (Exception exr)
{
logger.Error(exr, exr.Message);
}
finally
{
if (fStreamLog != null)
{
//释放流
fStreamLog.Close();
}
if (bReaderLog != null)
{
bReaderLog.Close();
}
}
#endregion var uploadFileName = HttpContext.Current.Request.Form["UploadFileName"]; Bussiness<bool> result = new Bussiness<bool>();
FileStream fStream = null;
BinaryReader bReader = null;
try
{
long offset = 0; //客户端定义,从X开始往后写,该值由服务端GetFileLength方法提供
IEnumerable<string> hasOffsetList = new List<string>();
bool hasOffset = Request.Headers.TryGetValues("Offset", out hasOffsetList);
if (hasOffset && hasOffsetList.Any())
{
long.TryParse(hasOffsetList.First(), out offset);
}
var offsetStr = HttpContext.Current.Request.Form["Offset"];
if (!string.IsNullOrEmpty(offsetStr))
{
long.TryParse(offsetStr, out offset);
}
if (string.IsNullOrEmpty(uploadFileName))
{
result.BussinessCode = -1;
result.BussinessMsg = "uploadFileName 上传文件名不能为空";
result.BussinessData = false;
return result;
}
//设置文件存放路径
//string dir = HttpContext.Current.Server.MapPath(SavePath);
string dir = SavePath;
//如果不存在文件夹,就创建文件夹
if (!Directory.Exists(dir))
Directory.CreateDirectory(dir);
//////var fileName = dir + "\\" + file.FileName; ///TODO
var fileName = dir + "\\" + (string.IsNullOrEmpty(uploadFileName) ? $"{DateTime.Now.ToString("HHmmss")}.txt" : uploadFileName);
fStream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
//偏移指针
fStream.Seek(offset, SeekOrigin.Begin); if (HttpContext.Current.Request.Files.Count > 0)
{
#region 文件形式 HttpPostedFile file = HttpContext.Current.Request.Files["UploadFile"];
int upLoadLength = Convert.ToInt32(file.InputStream.Length);
//从客户端的请求中获取文件流
bReader = new BinaryReader(file.InputStream);
byte[] data = new byte[upLoadLength];
bReader.Read(data, 0, upLoadLength); //将上传文件流读到byte[]中
fStream.Write(data, 0, upLoadLength);//将byte[]写到文件中, logger.Info($"上传文件 {uploadFileName} Offset => {offset} File.ContentLength => {upLoadLength} => {fileName}");
#endregion
}
else
{
#region Base64 //如果没传文件是以byte[]
var byteFile = HttpContext.Current.Request.Form["UploadFile"];
byte[] byteArray = Convert.FromBase64String(byteFile);
int upLoadLength = Convert.ToInt32(byteArray.Length);
fStream.Write(byteArray, 0, upLoadLength);//将byte[]写到文件中,
logger.Info($"上传文件 {uploadFileName} Offset => {offset} File.ContentLength => {upLoadLength} => {fileName}"); #endregion
}
result.BussinessData = true;
result.BussinessMsg = $"上传成功!";
result.BussinessCode = 0;
}
catch (Exception ex)
{
logger.Error(ex, ex.Message);
result.BussinessCode = -1;
result.BussinessMsg = ex.Message;
result.BussinessData = false; #region 出异常后,看看客户端上传的啥 FileStream fstreamErr = null;
BinaryReader readerErr = null;
try
{
fstreamErr = new FileStream(SavePath + "\\" + $"{uploadFileName}_{DateTime.Now:HHmmss}.err", FileMode.OpenOrCreate, FileAccess.ReadWrite);
int upLoadLength = (int)HttpContext.Current.Request.InputStream.Length;
readerErr = new BinaryReader(HttpContext.Current.Request.InputStream);
byte[] data = new byte[upLoadLength];
readerErr.Read(data, 0, upLoadLength); //将上传文件流读到byte[]中
fstreamErr.Write(data, 0, upLoadLength); //将byte[]写到文件中,
}
catch (Exception exr)
{
logger.Error(exr, exr.Message);
}
finally
{
if (fstreamErr != null)
{
//释放流
fstreamErr.Close();
}
if (readerErr != null)
{
readerErr.Close();
}
} #endregion return result;
}
finally
{
if (fStream != null)
{
//释放流
fStream.Close();
}
if (bReader != null)
{
bReader.Close();
}
}
return result;
}
上传前,源和目标文件对比

用 Postman 测试
先获取已上传文件的大小,供下面设置偏移量使用



上传后的源和目标文件对比

java 客户端代码
package com.vipsoft.demo.Controller; import org.springframework.core.io.FileSystemResource;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate; import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.RandomAccessFile;
import java.util.Base64; @RestController
@RequestMapping("/demo")
public class DemoController { @GetMapping(value = "/test")
public String login() {
return "这是demo下面的,用来写测试代码,测试通过后,移到正式项目中!";
} @GetMapping(value = "/uploadFile")
public String uploadFile(HttpServletRequest request) throws Exception { String url = "http://localhost:44999/api/Upload/UploadFile";
RestTemplate restTemplate = new RestTemplate();
String filePath = "D:\\Projects\\TEST.DAT";
File file = new File(filePath);
FileSystemResource resource = new FileSystemResource(file);
MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
param.add("Offset", "6");
param.add("UploadFileName", "ABC.txt");
param.add("UploadFile", resource); String rev = restTemplate.postForObject(url, param, String.class);
System.out.println(rev);
return rev;
} @GetMapping(value = "/uploadByte")
public String uploadByte(HttpServletRequest request) throws Exception {
String url = "http://localhost:44999/api/Upload/UploadFile";
RestTemplate restTemplate = new RestTemplate();
String filePath = "D:\\Projects\\TEST.DAT";
File file = new File(filePath);
//每次上传 10KB
int step = 10 * 1024;
for (long i = 0; i <= file.length(); i = i + step) {
//偏移量
long offset = i;
byte[] bytes = new byte[step];
//如果超过了就取最后的。
if (i + step > file.length()) {
bytes = new byte[(int) (file.length() - i)];
}
RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(offset);
int readSize = raf.read(bytes);
MultiValueMap<String, Object> param = new LinkedMultiValueMap<>();
param.add("Offset", i);
param.add("UploadFileName", "ABC.txt");
//转成 Base64
param.add("UploadFile", Base64.getEncoder().encodeToString(bytes));
String rev = restTemplate.postForObject(url, param, String.class);
//如果接口返回值出错,break
System.out.println(rev);
}
return "";
} }
C# 客户端伪代码
/// <summary>
/// 客户端上传伪代码
/// </summary>
/// <param name="fileName">待上传文件全路径</param>
/// <param name="byteCount">上传时的流量控制,文件较大时,用于切割文件上传</param>
/// <param name="msg">错误信息</param>
/// <returns>成功或者失败</returns>
public static bool UpLoadFile(string fileName, int byteCount, out string msg)
{
msg = "";
bool result = true;
long cruuent = GetServerFileLength(fileName); //客户端需要读取服务器已上传了多少内容,然后从偏移量开始往后读取发送 FileStream fStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader bReader = new BinaryReader(fStream);
long length = fStream.Length; fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1); #region 开始上传文件
try
{
#region 续传处理
byte[] data;
if (cruuent > 0)
{
fStream.Seek(cruuent, SeekOrigin.Current);
}
#endregion #region 分割文件上传
for (; cruuent <= length; cruuent = cruuent + byteCount)
{
try
{
if (cruuent + byteCount > length)
{
data = new byte[Convert.ToInt64((length - cruuent))];
bReader.Read(data, 0, Convert.ToInt32((length - cruuent)));
}
else
{
data = new byte[byteCount];
bReader.Read(data, 0, byteCount);
} Hashtable parms = new Hashtable();
parms.Add("Offset", cruuent.ToString());
var falg= PostData("",param);
if (falg == false)
{
break;
} }
catch (Exception ex)
{
msg = ex.ToString();
result = false;
break;
}
#endregion
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
bReader.Close();
fStream.Close();
}
GC.Collect();
#endregion
return result;
}
断点续传(上传)C#版的更多相关文章
- wepy开发小程序 大坑....本地调试ok,小程序上传体验版 组件出现问题
如果你碰到的上述问题(本地调试ok,小程序上传体验版 各种莫名其妙的问题-卡死-组件属性失效-$apply()不起作用) 您需要关闭 微信开发者工具中: 1.微信开发者工具-->项目--> ...
- .net 实现上传文件分割,断点续传上传文件
一 介绍 断点续传搜索大部分都是下载的断点续传,涉及到HTTP协议1.1的Range和Content-Range头. 来个简单的介绍 所谓断点续传,也就是要从文件已经下载的地方开始继续下载.在以前版本 ...
- java实现多线程断点续传,上传下载
采用apache 的 commons-net-ftp-ftpclient import java.io.File; import java.io.FileOutputStream; import ja ...
- java http大文件断点续传上传
因为需要研究下断点上传的问题.找了很久终于找到一个比较好的项目. 效果: 上传中,显示进度,时间,百分比. 点击[Pause]暂停,点击[Resume]继续. 2,代码分析 项目进行了封装使用最简单的 ...
- h5图片上传简易版(FileReader+FormData+ajax)
一.选择图片(input的file类型) <input type="file" id="inputImg"> 1. input的file类型会渲染为 ...
- java文件断点续传上传下载解决方案
这里只写后端的代码,基本的思想就是,前端将文件分片,然后每次访问上传接口的时候,向后端传入参数:当前为第几块文件,和分片总数 下面直接贴代码吧,一些难懂的我大部分都加上注释了: 上传文件实体类: 看得 ...
- 关于:基于http协议大文件断点续传上传至web服务器
关键部分 前端用file.slice()分块 前端用FileReader获取每一分块的md5值 后端用MultipartFile接受分块文件 后端用FileOutputStream拼装分块文件 话不多 ...
- wangeditor 支持上传视频版
1.关于使用哪个富文本编辑器. 简单的要求,不要求发布出来的文章排版要求很高. 可用wangediter.(简单,体积小,不可修改上传图片的尺寸大小) 转载 来源: https://blog.csd ...
- h5语音录制及上传(Java版语音聊天系统)
Since Chrome version 47, Voice Recording works only on HTTPS sites 目前基于webikit(谷歌之类的webikit)和Gecko(F ...
- django文件批量上传-简写版
模板中创建表单 <form method='post' enctype='multipart/form-data' action='/upload/'> <input type='f ...
随机推荐
- 解决ADS1.2与MDK4.7冲突问题
需要添加2个系统变量. 1,在我的电脑点击属性--->高级--->环境变量---->系统变量,增加环境变量名: ARMCC5LIB 变量值:C:\Keil\ARM\ARMCC\lib ...
- 文心一言 VS 讯飞星火 VS chatgpt (134)-- 算法导论11.2 6题
六.用go语言,假设将n 个关键字存储到一个大小为 m 且通过链接法解决冲突的散列表中,同时已知每条链的长度,包括其中最长链的长度 L,请描述从散列表的所有关键字中均匀随机地选择某一元素并在 O(L· ...
- 学会XPath,轻松抓取网页数据
一.定义 XPath(XML Path Language)是一种用于在 XML 文档中定位和选择节点的语言.XPath的选择功能非常强大,可以通过简单的路径选择语法,选取文档中的任意节点或节点集.学会 ...
- 文心一言 VS 讯飞星火 VS chatgpt (146)-- 算法导论12.2 1题
一.用go语言,假设一棵二叉搜索树中的结点在1到 1000 之间,现在想要查找数值为 363 的结点.下面序列中哪个不是查找过的序列? a.2,252,401,398,330,344,397,363. ...
- MAUI+Masa Blazor APP 各大商店新手发布指南-华为篇
目录 前言 准备材料 一.企业认证 二.审核资料 审核注意事项 总结 前言 AppGallery Connect(简称AGC)是华为应用市场推出的应用一站式服务平台,致力于为开发者提供应用创意.开发. ...
- Linux笔记02: Linux环境_2.2 Linux系统安装
2.2 Linux系统 本文使用的Linux系统为CentOS 7.9.2009,读者可以根据自己的需要选择不同的版本. 2.2.1 CentOS版本 CentOS基本上是安装在i386.x86_64 ...
- [AGC59C] Guessing Permutation for as Long as Possible
Problem Statement A teacher has a hidden permutation $P=(P_1,P_2,\ldots,P_N)$ of $(1,2,\cdots,N)$. Y ...
- 【软件安装】vmware虚拟机安装完整教程(15.5版本)
目录 一.基础介绍 二.准备工作(注意:如果自己下载不下来翻到最下面获取下载地址) 三.VMware下载与安装 VMware Workstation15.5新功能 注意: 一.基础介绍 VMware ...
- 微调baichuan2-7b遇到的显存坑
问题描述: 微调baichuan2-7b模型,验证一轮后继续训练第一个iteration显存大幅增加 项目链接: https://github.com/wp931120/baichuan_sft_lo ...
- 【Python】【OpenCV】定位条形码(二)moments和HuMoments
根据上一篇博客可知,单纯的通过求取最大面积而进行定位的局限性,因此我们接下来将通过cv2.moments()和cv2.HuMoments()这两个方法来在更复杂的环境中去找到我们的目标区域. cv2. ...