断点续传(上传)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 ...
随机推荐
- 提升运维效率:轻松掌握JumpServer安装和使用技巧
前言 JumpServer 是一个开源的跳板机的解决方案,提供了对远程服务器的安全访问.会话录制和审计.用户身份管理等功能,适用于需要管理机器资源&大量服务器资源的情况. 本文将在分享 doc ...
- 可怕!.Net 8正式发布了,.Net野心确实不小!
随着三天.NET Conf 2023的会议结束了,.Net 8正式发布了. .Net 8是官方号称有史以来性能最快的一个版本了. .Net 8 增加了数以千计的性能.稳定性和安全性改进,以及平台和工具 ...
- 使用 Hexo 搭建个人博客并部署到云服务器
目录 1 整体流程 2. 本地环境准备 2.1 安装 Node.js 和 Git 2.2 安装 Hexo 3. 服务端环境准备 3.1 Nginx 环境配置 3.1.1 安装 Nginx 3.1.2 ...
- Video教程介绍(开篇)
教程简介 本文将简单描述视频网站教程,视频网站是一个类似于腾讯视频一样的网站,视频资源用户自己上传,然后提供友好的界面查看视频和搜索视频,并且提供管理页面对于视频进行管理,我们将使用Blazor作为前 ...
- 工厂模式(Factory Method)
模式定义 定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使得一个类的实例化延迟(目的:解耦)到子类. 要点总结 Factory Method模式用于隔离类对象的使用 ...
- 【Android】学习day05|简单登陆页面的实现|监听代码
实现效果如下图所示 实现代码[部分] MainActivity.java 1 package com.example.app02; 2 3 import androidx.appcompat.app. ...
- Echarts 柱形图最全详解
Echarts 是一款基于 JavaScript 的开源可视化图表库,被广泛应用于数据可视化领域.它提供了丰富的图表类型和交互功能,其中柱形图是最常用和重要的一种图表类型之一.下面是对 Echarts ...
- 如何收集pod重启前现场
之前分享过几篇优化pod重启的文章,有朋友发私信问:看你的优化文章很过瘾,可否分享下如何收集pod重启前的现场. 案例分享-full gc导致k8s pod重启 记一次k8s pod频繁重启的优化之旅 ...
- jmeter测试计划中的“独立运行每个线程组”Demo演示
一:jmeter的运行顺序 测试计划-->线程组 其次执行顺序为:配置元件.前置处理器.定时器.取样器.后置处理器.断言.监听器 当一个测试计划中有多个线程组,当多个线程组都是是执行状态时,就会 ...
- 生物电势测量ECG
参考来源:ADI官网技术文章.知乎(hxl695822705.KingPo-张超.津发科技.木森.深圳加1健康科技) ECG的产生 ECG(Electrocardiogram)心电测量,是指人体内窦房 ...