Html5 js上传插件resumable.js 的使用

  最近做一个csv文件上传,网上找了几个,兼容性不好,年代也比较久远,就去github上看看找找,发现了一个resumable.js,支持分片上传,多文件上传,完全满足需求~项目地址:https://github.com/23/resumable.js。

  简单说下应用,顺便保存下代码,万一哪天再用了,忘了还得重新找.....这才是关键。

  后台代码,两个文件,一个model,一个webapi,基于C#的。

  model代码:

namespace Resumable.Models
{
	public class ResumableConfiguration
	{
		/// <summary>
		/// Gets or sets number of expected chunks in this upload.
		/// </summary>
		public int Chunks { get; set; }

		/// <summary>
		/// Gets or sets unique identifier for current upload.
		/// </summary>
		public string Identifier { get; set; }

		/// <summary>
		/// Gets or sets file name.
		/// </summary>
		public string FileName { get; set; }

		public ResumableConfiguration()
		{

		}

		/// <summary>
		/// Creates an object with file upload configuration.
		/// </summary>
		/// <param name="identifier">Upload unique identifier.</param>
		/// <param name="filename">File name.</param>
		/// <param name="chunks">Number of file chunks.</param>
		/// <returns>File upload configuration.</returns>
		public static ResumableConfiguration Create(string identifier, string filename, int chunks)
		{
			return new ResumableConfiguration { Identifier = identifier, FileName = filename, Chunks = chunks };
		}
	}
}

  API代码:

using Resumable.Models;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;

namespace Resumable.Controllers
{
	[RoutePrefix("api/File")]
	public class FileUploadController : ApiController
	{
		private string root = System.Web.Hosting.HostingEnvironment.MapPath("~/upload"); 

		[Route("Upload"), HttpOptions]
		public object UploadFileOptions()
		{
			return Request.CreateResponse(HttpStatusCode.OK);
		}

		[Route("Upload"), HttpGet]
		public object Upload(int resumableChunkNumber, string resumableIdentifier)
		{
			return ChunkIsHere(resumableChunkNumber, resumableIdentifier) ? Request.CreateResponse(HttpStatusCode.OK) : Request.CreateResponse(HttpStatusCode.NoContent);
		}

		[Route("Upload"), HttpPost]
		public async Task<object> Upload()
		{
			// Check if the request contains multipart/form-data.
			if (!Request.Content.IsMimeMultipartContent())
			{
				throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
			}
			if (!Directory.Exists(root)) Directory.CreateDirectory(root);
			var provider = new MultipartFormDataStreamProvider(root);

			if (await readPart(provider))
			{
				// Success
				return Request.CreateResponse(HttpStatusCode.OK);
			}
			else
			{
				// Fail
				var message = DeleteInvalidChunkData(provider) ? "Cannot read multi part file data." : "Cannot delete temporary file chunk data.";
				return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, new System.Exception(message));
			}
		}

		private static bool DeleteInvalidChunkData(MultipartFormDataStreamProvider provider)
		{
			try
			{
				var localFileName = provider.FileData[0].LocalFileName;
				if (File.Exists(localFileName))
				{
					File.Delete(localFileName);
				}
				return true;
			}
			catch {
				return false;
			}
		}

		private async Task<bool> readPart(MultipartFormDataStreamProvider provider)
		{
			try
			{
				await Request.Content.ReadAsMultipartAsync(provider);
				ResumableConfiguration configuration = GetUploadConfiguration(provider);
				int chunkNumber = GetChunkNumber(provider);

				// Rename generated file
				MultipartFileData chunk = provider.FileData[0]; // Only one file in multipart message
				RenameChunk(chunk, chunkNumber, configuration.Identifier);

				// Assemble chunks into single file if they‘re all here
				TryAssembleFile(configuration);
				return true;
			}
			catch {
				return false;
			}
		}

		#region Get configuration

		[NonAction]
		private ResumableConfiguration GetUploadConfiguration(MultipartFormDataStreamProvider provider)
		{
			return ResumableConfiguration.Create(identifier: GetId(provider), filename: GetFileName(provider), chunks: GetTotalChunks(provider));
		}

		[NonAction]
		private string GetFileName(MultipartFormDataStreamProvider provider)
		{
			var filename = provider.FormData["resumableFilename"];
			return !String.IsNullOrEmpty(filename) ? filename : provider.FileData[0].Headers.ContentDisposition.FileName.Trim(‘\"‘);
		}

		[NonAction]
		private string GetId(MultipartFormDataStreamProvider provider)
		{
			var id = provider.FormData["resumableIdentifier"];
			return !String.IsNullOrEmpty(id) ? id : Guid.NewGuid().ToString();
		}

		[NonAction]
		private int GetTotalChunks(MultipartFormDataStreamProvider provider)
		{
			var total = provider.FormData["resumableTotalChunks"];
			return !String.IsNullOrEmpty(total) ? Convert.ToInt32(total) : 1;
		}

		[NonAction]
		private int GetChunkNumber(MultipartFormDataStreamProvider provider)
		{
			var chunk = provider.FormData["resumableChunkNumber"];
			return !String.IsNullOrEmpty(chunk) ? Convert.ToInt32(chunk) : 1;
		}

		#endregion

		#region Chunk methods

		[NonAction]
		private string GetChunkFileName(int chunkNumber, string identifier)
		{
			return Path.Combine(root, string.Format("{0}_{1}", identifier, chunkNumber.ToString()));
		}

		[NonAction]
		private void RenameChunk(MultipartFileData chunk, int chunkNumber, string identifier)
		{
			string generatedFileName = chunk.LocalFileName;
			string chunkFileName = GetChunkFileName(chunkNumber, identifier);
			if (File.Exists(chunkFileName)) File.Delete(chunkFileName);
			File.Move(generatedFileName, chunkFileName);

		}

		[NonAction]
		private string GetFilePath(ResumableConfiguration configuration)
		{
			return Path.Combine(root, configuration.Identifier);
		}

		[NonAction]
		private bool ChunkIsHere(int chunkNumber, string identifier)
		{
			string fileName = GetChunkFileName(chunkNumber, identifier);
			return File.Exists(fileName);
		}

		[NonAction]
		private bool AllChunksAreHere(ResumableConfiguration configuration)
		{
			for (int chunkNumber = 1; chunkNumber <= configuration.Chunks; chunkNumber++)
				if (!ChunkIsHere(chunkNumber, configuration.Identifier)) return false;
			return true;
		}

		[NonAction]
		private void TryAssembleFile(ResumableConfiguration configuration)
		{
			if (AllChunksAreHere(configuration))
			{
				// Create a single file
				var path = ConsolidateFile(configuration);

				// Rename consolidated with original name of upload
				RenameFile(path, Path.Combine(root, configuration.FileName));

				// Delete chunk files
				DeleteChunks(configuration);
			}
		}

		[NonAction]
		private void DeleteChunks(ResumableConfiguration configuration)
		{
			for (int chunkNumber = 1; chunkNumber <= configuration.Chunks; chunkNumber++)
			{
				var chunkFileName = GetChunkFileName(chunkNumber, configuration.Identifier);
				File.Delete(chunkFileName);
			}
		}

		[NonAction]
		private string ConsolidateFile(ResumableConfiguration configuration)
		{
			var path = GetFilePath(configuration);
			using (var destStream = File.Create(path, 15000))
			{
				for (int chunkNumber = 1; chunkNumber <= configuration.Chunks; chunkNumber++)
				{
					var chunkFileName = GetChunkFileName(chunkNumber, configuration.Identifier);
					using (var sourceStream = File.OpenRead(chunkFileName))
					{
						sourceStream.CopyTo(destStream);
					}
				}
				destStream.Close();
			}

			return path;
		}

		#endregion

		[NonAction]
		private string RenameFile(string sourceName, string targetName)
		{
			targetName = Path.GetFileName(targetName); // Strip to filename if directory is specified (avoid cross-directory attack)
			string realFileName = Path.Combine(root, targetName);
			if (File.Exists(realFileName)) File.Delete(realFileName);
			File.Move(sourceName, realFileName);
			return targetName;
		}
	}
}

 github上给的demo里边的代码~完全可以拿来用。然而并没有webapp的代码,我照着java的抄,发生了悲剧。不过稍微改改就好。

贴出来我的代码

<div id="frame">
    <link href="~/Content/resumablestyle.css" rel="stylesheet" />
    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
    <script src="~/Scripts/resumable.js"></script>
    <br />
    <div class="resumable-drop" ondragenter="jQuery(this).addClass(‘resumable-dragover‘);" ondragend="jQuery(this).removeClass(‘resumable-dragover‘);" ondrop="jQuery(this).removeClass(‘resumable-dragover‘);">
        将文件拖拽到此处上传 <a class="resumable-browse"><u>点击选择要上传的文件</u></a>
    </div>
    <div class="resumable-progress">
        <table>
            <tr>
                <td width="100%"><div class="progress-container"><div class="progress-bar"></div></div></td>
                <td class="progress-text" nowrap="nowrap"></td>
                <td class="progress-pause" nowrap="nowrap">
                    <a href="#" onclick="r.upload(); return(false);" class="progress-resume-link"><img src="~/Img/resume.png" title="Resume upload" /></a>
                    <a href="#" onclick="r.pause(); return(false);" class="progress-pause-link"><img src="~/Img/pause.png" title="Pause upload" /></a>
                </td>
            </tr>
        </table>
    </div>

    <ul class="resumable-list"></ul>
    <script>
        var r = new Resumable({
            target: ‘@Url.Content("~/api/File/Upload")‘,
            chunkSize: 1 * 1024 * 1024,
            simultaneousUploads: 3,
            //testChunks: false,
            throttleProgressCallbacks: 1,
            fileType: ["csv"]
            //method: "octet"
        });
        // Resumable.js isn‘t supported, fall back on a different method
        if (!r.support) {
            $(‘.resumable-error‘).show();
        } else {
            // Show a place for dropping/selecting files
            $(‘.resumable-drop‘).show();
            r.assignDrop($(‘.resumable-drop‘)[0]);
            r.assignBrowse($(‘.resumable-browse‘)[0]);

            // Handle file add event
            r.on(‘fileAdded‘, function (file) {
                // Show progress pabr
                $(‘.resumable-progress, .resumable-list‘).show();
                // Show pause, hide resume
                $(‘.resumable-progress .progress-resume-link‘).hide();
                $(‘.resumable-progress .progress-pause-link‘).show();
                // Add the file to the list
                $(‘.resumable-list‘).append(‘<li class="resumable-file-‘ + file.uniqueIdentifier + ‘">Uploading <span class="resumable-file-name"></span> <span class="resumable-file-progress"></span>‘);
                $(‘.resumable-file-‘ + file.uniqueIdentifier + ‘ .resumable-file-name‘).html(file.fileName);
                // Actually start the upload
                r.upload();
            });
            r.on(‘pause‘, function () {
                // Show resume, hide pause
                $(‘.resumable-progress .progress-resume-link‘).show();
                $(‘.resumable-progress .progress-pause-link‘).hide();
            });
            r.on(‘complete‘, function () {
                // Hide pause/resume when the upload has completed
                $(‘.resumable-progress .progress-resume-link, .resumable-progress .progress-pause-link‘).hide();
            });
            r.on(‘fileSuccess‘, function (file, message) {
                // Reflect that the file upload has completed
                $(‘.resumable-file-‘ + file.uniqueIdentifier + ‘ .resumable-file-progress‘).html(‘(completed)‘);

            });
            r.on(‘fileError‘, function (file, message) {
                // Reflect that the file upload has resulted in error
                $(‘.resumable-file-‘ + file.uniqueIdentifier + ‘ .resumable-file-progress‘).html(‘(file could not be uploaded: ‘ + message + ‘)‘);
            });
            r.on(‘fileProgress‘, function (file) {
                // Handle progress for both the file and the overall upload
                $(‘.resumable-file-‘ + file.uniqueIdentifier + ‘ .resumable-file-progress‘).html(Math.floor(file.progress() * 100) + ‘%‘);
                $(‘.progress-bar‘).css({ width: Math.floor(r.progress() * 100) + ‘%‘ });
            });
        }
    </script>
</div>

  css样式,图标文件,都是用的demo里的。直接用就好。css中主要的就是:

/* Reset */
#frame {margin:0 auto; width:800px; text-align:left;}

/* Uploader: Drag & Drop */
/*.resumable-error {display:none; font-size:14px; font-style:italic;}
.resumable-drop {padding:15px; font-size:13px; text-align:center; color:#666; font-weight:bold;background-color:#eee; border:2px dashed #aaa; border-radius:10px; margin-top:40px; z-index:9999; display:none;}
.resumable-dragover {padding:30px; color:#555; background-color:#ddd; border:1px solid #999;}*/
.resumable-error {display:none; font-size:14px; font-style:italic;}
.resumable-drop { padding:15px;font-size:13px; text-align:center; color:#666; font-weight:bold;background-color:#eee; border:2px dashed #aaa; border-radius:10px;  z-index:9999; display:none;}
.resumable-dragover {padding:30px; color:#555; background-color:#ddd; border:1px solid #999;}
/* Uploader: Progress bar */
.resumable-progress {margin:30px 0 30px 0; width:100%; display:none;}
.progress-container {height:7px; background:#9CBD94; position:relative; }
.progress-bar {position:absolute; top:0; left:0; bottom:0; background:#45913A; width:0;}
.progress-text {font-size:11px; line-height:9px; padding-left:10px;}
.progress-pause {padding:0 0 0 7px;}
.progress-resume-link {display:none;}
.is-paused .progress-resume-link {display:inline;}
.is-paused .progress-pause-link {display:none;}
.is-complete .progress-pause {display:none;}

/* Uploader: List of items being uploaded */
.resumable-list {overflow:auto; margin-right:-20px; display:none;}
.uploader-item {width:148px; height:90px; background-color:#666; position:relative; border:2px solid black; float:left; margin:0 6px 6px 0;}
.uploader-item-thumbnail {width:100%; height:100%; position:absolute; top:0; left:0;}
.uploader-item img.uploader-item-thumbnail {opacity:0;}
.uploader-item-creating-thumbnail {padding:0 5px; font-size:9px; color:white;}
.uploader-item-title {position:absolute; font-size:9px; line-height:11px; padding:3px 50px 3px 5px; bottom:0; left:0; right:0; color:white; background-color:rgba(0,0,0,0.6); min-height:27px;}
.uploader-item-status {position:absolute; bottom:3px; right:3px;}

/* Uploader: Hover & Active status */
.uploader-item:hover, .is-active .uploader-item {border-color:#4a873c; cursor:pointer; }
.uploader-item:hover .uploader-item-title, .is-active .uploader-item .uploader-item-title {background-color:rgba(74,135,60,0.8);}

/* Uploader: Error status */
.is-error .uploader-item:hover, .is-active.is-error .uploader-item {border-color:#900;}
.is-error .uploader-item:hover .uploader-item-title, .is-active.is-error .uploader-item .uploader-item-title {background-color:rgba(153,0,0,0.6);}
.is-error .uploader-item-creating-thumbnail {display:none;}

  基本就这么多,简单粗暴.....效果还是很好的,能实现大文件分片上传,多文件上传处理,自带进度条提示,省了好多事,说下参数含义:target:后台API,chunkSize:分片大小,fileType:文件类型。

时间: 2024-10-08 10:44:15

Html5 js上传插件resumable.js 的使用的相关文章

图片上传插件用法,JS语法【三】

注意点: 作为文件域(<input type="file">)必须要有name属性,如果没有name属性,上传之后服务器是获取不到图片的.如:正确的写法是<input type="file" id="file1" name="file1" /> dataType参数一定要大写.如:dataType: 'HTML'. HTML <body> <p><input type=&q

Ajaxupload.js上传插件使用

注意一下火狐,360IE78下的坑: 返回过来的response在不同浏览器下的字符串不一致 // response(chrome):<pre style="word-wrap: break-word; white-space: pre-wrap;">{"success":true,"info":"保存成功!","PhotoURL":"\/upload_BenefitsFund\/33

cjhupload一个简单异步文件上传插件(html5+js)

来源:http://www.myopenresources.com/page/resource_detail_0.html?rid=370 更多文章请查看本人博客网站:http://www.myopenresources.com cjhupload是一个本人基于原生JS编写的一个文件上传插件,支持手机.电脑端,你可查看例子,或下载详细例子(请到下面的"下载地址"下载). 例子: <!DOCTYPE HTML> <html lang='zh'> <head&

CKeditor七牛云JS SDK前端上传插件修改

七牛云官方有放出JS SDK,没有我想使用的CKeditor前端上传插件,所以结合七牛官方的Javascript SDK对CKeditor做了一些修改使它能够直接上传到七牛云,又同时保留了上传到本地服务的接口. 优点和缺点1.在前端上传到七牛云,不消耗服务器带宽和流量.空间.2.保留了CKeditor上传到自己服务器的能力.3.支持拖拽和剪切板黏贴图片上传(因为是保存为png格式,建议只黏贴色彩单调的图片,要不然图片会很大,浪费流量).4.拖拽和剪切板黏贴图片.不支持4M以上的文件,因为没有分块

7款js文件上传插件

1.  jQuery File Upload 具有多文件上传.拖拽.进度条和图像预览功能的文件上传插件,支持跨域.分块.暂停恢复和客户端图像缩放.可与任何服务端平台(如PHP.Python.Ruby on Rails.Java.Node.js.Go等)一起使用,支持标准的HTML表单文件上传. 2.  Pixelcone Fileuploader 使用HTML5 API的jQuery文件上传插件,支持AJAX上传和拖拽操作,以及针对老版本浏览器的iframe上传部件.有多种形式来实现多文件上传,

纯原生js移动端图片压缩上传插件

前段时间,同事又来咨询一个问题了,说手机端动不动拍照就好几M高清大图,上传服务器太慢,问问我有没有可以压缩图片并上传的js插件,当然手头上没有,别慌,我去网上搜一搜. 结果呢,呵呵...诶~又全是基于jquery.zepto的(这句话似乎吐槽次数太多了...),然后我也就不吐槽了, 然后当然是自己做了,先上图: 纯原生js的移动端图片压缩上传插件,不依赖任何库 用法 在html页面中引入input标签,通过自定义属性data-LUploader绑定点击触发的标签id,写法如下: <div cla

js上传文件

一.原始的XMLHttpRequestjs上传文件过程(参考地址:http://blog.sina.com.cn/s/blog_5d64f7e3010127ns.html) 用到两个对象 第一个对象:FormData 第二个对象:XMLHttpRequest 目前新版的Firefox 与 Chrome 等支持HTML5的浏览器完美的支持这两个对象,但IE9尚未支持 FormData 对象,还在用IE6 ? 只能仰天长叹.... 有了这两个对象,我们可以真正的实现Ajax方式上传文件. 示例代码:

HTML5文件上传组件美化jQuery插件

简要教程 jQuery.filer是一款简单的HTML5文件上传组件美化jQuery插件.它能够完成单文件和多文件的上传,支持文件的拖拽,支持不同的文件格式校验,支持缩略图和图标等,是一款非常实用的文件上传插件.它的特点还有: 对文件上传File Input组件进行美化 支持多文件上传 支持校验文件:大小,扩展名等 支持创建文件的缩略图 每种类型的文件可以自定义图标 可以为缩略图,图标和input自定义模板和主题 可以移出已选择的文件 可以从剪切板粘贴图片 所有的图标在一个字体文件中 支持文件拖

原生js上传文件 显示进度条

最近在做文件上传的功能,因为界面设计比较简单,就没有引用jq,但是网上大部分的上传插件都需要jq的支持.为了一个上传功能引用90多k的jq文件有点太小题大做了,所以就自己动手写了一个原生js上传的demo.下面是代码: HTML代码 <html> <head> <title></title> </head> <body> <input type="file" id="f" /> &l