.Net 大文件+多线程上传控件(Activex)

之前项目中碰到,IIS上传大文件报错的问题,查了下是iis的设置问题,改吧改吧就好了,总感觉不爽,就自己写了一个大文件上传的activex,无奈,本人只有.net做的好点,就用.net写了一个,当然了,主要用的还是C#。

   怎么编写activex网上有很多,大家百度下,谷歌下,都出来了。

   我就把代码发出来,有要的可以研究下,注释什么的,还是很规范的。

Activex部分:

UploadActivexCtrl
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.Drawing;
 using System.Data;
 using System.Globalization;
 using System.IO;
 using System.Linq;
 using System.Net;
 using System.Runtime.InteropServices;
 using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Web;
 using System.Windows.Forms;
                  
 namespace MutifileUploadCtrl
 {
     [ComVisible(true)]
     [Guid("C4F9F24F-B860-4e79-945D-B9A281950C82")]
     [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
     public interface IUploadControlComEvents
     {
         [DispId(0x10000002)]
         void OnUploaded();
         [DispId(0x10000003)]
         void OnStatusChanged(String status);
     }
 //
 //     [Guid("4B3AE7D8-FB6A-4558-8A96-BF82B54F329C")]
 //     [ComVisible(true)]
 //     public interface IUploadControlComOjbect
 //     {
 //         [DispId(0x10000001)]
 //         void Upload(String filePaths, String saveFileNames);
 //     }
                  
     [Guid("6e60ddbf-84fa-4d8f-b479-60879c861686"),
        ComSourceInterfaces(typeof(IUploadControlComEvents)),
        ClassInterface(ClassInterfaceType.AutoDual),
        // ComDefaultInterface(typeof(IUploadControlComOjbect)),
        // ClassInterface(ClassInterfaceType.None),
        ComVisible(true)]
      public class UploadControl : UserControl, IObjectSafety
      {
         [ComVisible(true)]
         public String SvrAddr { get; set; }
                  
         [ComVisible(true)]
         public delegate void OnUploadedEventHanlder();
         public event OnUploadedEventHanlder OnUploaded;
                  
         [ComVisible(true)]
         public delegate void OnStatusChangedEventHanlder(String status);
         public event OnStatusChangedEventHanlder OnStatusChanged;
                  
         // 每次上传1M
         private const Int32 BUFFER_SIZE = 1024 * 1024;
                  
         [ComVisible(true)]
         public void Upload(String filePaths, String saveFileNames)
         {
             var paths = filePaths.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);
             var fileNames = saveFileNames.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                  
             var factory = new TaskFactory();
                  
             factory.StartNew(() =>
             {
                 var tasks = new List<Task>();
                  
                 for (int index = 0; index < paths.Length; index++)
                 {
                     var path = paths[index];
                     var fileName = fileNames[index];
                     tasks.Add(factory.StartNew(() => UploadFile(path, fileName)));
                     //UploadFile(path, fileName);
                 }
                  
                 Task.WaitAll(tasks.ToArray());
                  
                 if (OnUploaded != null)
                 {
                     OnUploaded();
                 }
             });
         }
                  
         [ComVisible(false)]
         private void UploadFile(String filePath, String saveFileName)
         {
             var fileName = Path.GetFileName(filePath);
                  
             var stream = new FileStream(filePath, FileMode.Open);
                  
             var fileData = new Byte[BUFFER_SIZE];
                  
             var offset = 0;
                  
             var fileId = Guid.NewGuid().ToString();
                  
             var totalSize = stream.Length;
             var partCount = totalSize%BUFFER_SIZE == 0 ? totalSize/BUFFER_SIZE : totalSize/BUFFER_SIZE + 1;
                  
             // 将文件流转写入网络流
             var part = 1;
             var response = "";
             do
             {
                 var position = stream.Position;
                  
                 offset = stream.Read(fileData, 0, fileData.Length);
                  
                 if(offset == 0) break;
                  
                 response = PostData(fileData, fileId, saveFileName, position, offset, part, (Int32)partCount);
                  
                 if (OnStatusChanged != null)
                 {
                     OnStatusChanged(fileName + ";" + totalSize + ";" + position + ";" + offset);
                 }
                  
                 part++;
             } while (offset > 0 && response == "ok");
                  
             stream.Close();
             stream.Dispose();
         }
                         
         [ComVisible(false)]
         private String PostData(byte[] data, String fileId, String fileName, long position, Int32 size, Int32 part, Int32 partCount)
         {
             if (String.IsNullOrEmpty(SvrAddr)) return "";
                  
             var paras = "?FileId=" + HttpUtility.UrlEncode(fileId) +
                         "&PartNum=" + part +
                         "&Position=" + position +
                         "&FileSize=" + size +
                         "&FileName=" + HttpUtility.UrlEncode(fileName) +
                         "&PartCount=" + partCount;
                  
             var request = (HttpWebRequest)WebRequest.Create(SvrAddr + paras);
             request.Method = "POST";
             request.ContentLength = data.Length;
                  
             using (var stream = request.GetRequestStream())
             {
                 stream.Write(data, 0, data.Length);
                 stream.Close();
             }
                  
             using (var myResponse = (HttpWebResponse) request.GetResponse())
             {
                 var reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
                 return reader.ReadToEnd();
             }
         }
                  
         #region 实现IObjectSafety接口
         private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
         private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
         private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
         private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
         private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
                  
         private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
         private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
         private const int S_OK = 0;
         private const int E_FAIL = unchecked((int)0x80004005);
         private const int E_NOINTERFACE = unchecked((int)0x80004002);
                  
         private bool _fSafeForScripting = true;
         private bool _fSafeForInitializing = true;
         //使ActiveX控件成为安全的控件
         public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
         {
             int Rslt = E_FAIL;
             string strGUID = riid.ToString("B");
             pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;
             switch (strGUID)
             {
                 case _IID_IDispatch:
                 case _IID_IDispatchEx:
                     Rslt = S_OK;
                     pdwEnabledOptions = 0;
                     if (_fSafeForScripting == true)
                         pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                     break;
                 case _IID_IPersistStorage:
                 case _IID_IPersistStream:
                 case _IID_IPersistPropertyBag:
                     Rslt = S_OK;
                     pdwEnabledOptions = 0;
                     if (_fSafeForInitializing == true)
                         pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                     break;
                 default:
                     Rslt = E_NOINTERFACE;
                     break;
             }
                  
             return Rslt;
         }
                  
         public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
         {
             int Rslt = E_FAIL;
                  
             string strGUID = riid.ToString("B");
             switch (strGUID)
             {
                 case _IID_IDispatch:
                 case _IID_IDispatchEx:
                     if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
                         Rslt = S_OK;
                     break;
                 case _IID_IPersistStorage:
                 case _IID_IPersistStream:
                 case _IID_IPersistPropertyBag:
                     if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
                         Rslt = S_OK;
                     break;
                 default:
                     Rslt = E_NOINTERFACE;
                     break;
             }
                  
             return Rslt;
         }
         #endregion
     }
                  
     [Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
     public interface IObjectSafety
     {
         [PreserveSig]
         int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions);
                  
         [PreserveSig]
         int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask,
                                       [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions);
     }
                  
 }

后台处理部分:

UploadHandler
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
 using System.Web;
    
 namespace Server
 {
     public class ConfigFileEntry
     {
         public String FileId { get; set; }
         public String FileNameWithoutExtension { get; set; }
         public Int32 PartCount { get; set; }
         public String FileExtension { get; set; }
         public List<Int32> ReadyParts { get; set; }
     }
    
     /// <summary>
     /// Upload 的摘要说明
     /// </summary>
     public class Upload : IHttpHandler
     {
         private static Boolean _sign = false;
         const String CONFIG_FILE_EXTENSION = ".conf";
         private static String BASE_PATH;
         public void ProcessRequest(HttpContext context)
         {
             BASE_PATH = context.Server.MapPath("~/uploadfiles/");
    
             context.Response.ContentType = "text/plain";
             context.Response.HeaderEncoding = System.Text.Encoding.UTF8;
             context.Response.Charset = "utf-8";
    
             var fileId = HttpUtility.UrlDecode(context.Request["FileId"]);
             var fileName = HttpUtility.UrlDecode(context.Request["FileName"]);
             var position = int.Parse(context.Request["Position"]);
             var fileSize = int.Parse(context.Request["FileSize"]);
             var partNum = int.Parse(context.Request["PartNum"]);
             var fileExtension = Path.GetExtension(fileName);
             var partCount = int.Parse(context.Request["PartCount"]);
             var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
             var configFilePath = Path.Combine(BASE_PATH, fileNameWithoutExtension + CONFIG_FILE_EXTENSION);
    
             // 写入配置文件
             if (!File.Exists(configFilePath))
             {
                 WriteDataIntoConfigFile(configFilePath, fileId);
                 WriteDataIntoConfigFile(configFilePath, fileNameWithoutExtension);
                 WriteDataIntoConfigFile(configFilePath, partCount);
                 WriteDataIntoConfigFile(configFilePath, fileExtension);
             }
    
             var filePath = Path.Combine(BASE_PATH, fileNameWithoutExtension + "_" + partNum);
                
             WriteDataIntoDataFile(context, fileSize, filePath);
    
             // 启用检查线程,检测文件所有部分是否上传完成
             if (!_sign)
             {
                 _sign = true;
                 var thread = new Thread(MergeFile);
                 thread.Start();
             }
    
             // 判断写入文件大小是否等于上传大小
             var fileInfo = new FileInfo(filePath);
                
             if (fileInfo.Length == fileSize)
             {
                 // 把当前结果写入配置文件(表示当前part操作完成)
                 WriteDataIntoConfigFile(configFilePath, partNum);
             }
    
             context.Response.Write("ok");
         }
    
         /// <summary>
         /// 合并文件
         /// </summary>
         private void MergeFile()
         {
             do
             {
                 if (!_sign) break;
                 // 获取所有的配置文件
                 var configFiles = Directory.GetFiles(BASE_PATH, "*" + CONFIG_FILE_EXTENSION + "*");
    
                 foreach (var configFile in configFiles)
                 {
                     var fileName = Path.GetFileNameWithoutExtension(configFile);
                     var tempPath = Path.Combine(BASE_PATH, fileName + ".tmp");
                     // 移动文件
                     File.Copy(configFile, tempPath, true);
    
                     // 读取配置文件
                     var entry = ReadConfigFile(tempPath);
                     // 全部文件写入完成
                     if (entry.ReadyParts.Count == entry.PartCount)
                     {
                         // 删除配置文件
                         File.Delete(configFile);
                         // 合并文件
                         CombineFiles(entry.FileNameWithoutExtension, entry.FileExtension, entry.ReadyParts);
    
                         // 删除临时文件
                         File.Delete(tempPath);
                     }
                 }
    
                 Thread.Sleep(5000);
             } while (true);
    
                
             _sign = true;
         }
    
         /// <summary>
         /// 合并文件
         /// </summary>
         /// <param name="fileName"></param>
         /// <param name="fileExtension"></param>
         /// <param name="parts"></param>
         private void CombineFiles(String fileName, String fileExtension, List<Int32> parts)
         {
             var stream = new FileStream(Path.Combine(BASE_PATH, fileName + fileExtension), FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);
                
             for (var index = 1; index <= parts.Count; index ++)
             {
                 var dataFilePath = Path.Combine(BASE_PATH, fileName + "_" + index);
                 var position = (Int32)stream.Length;
                 var buffer = File.ReadAllBytes(dataFilePath);
                 stream.Write(buffer, 0, buffer.Length);
    
                 File.Delete(dataFilePath);
             }
    
             stream.Flush();
             stream.Close();
         }
    
         /// <summary>
         /// 读取配置文件
         /// </summary>
         /// <param name="tempPath"></param>
         /// <returns></returns>
         private ConfigFileEntry ReadConfigFile(String tempPath)
         {
             var stream = new FileStream(tempPath, FileMode.Open, FileAccess.Read, FileShare.Read);
             var reader = new StreamReader(stream);
    
             var entry = new ConfigFileEntry();
    
             entry.FileId = reader.ReadLine();
             entry.FileNameWithoutExtension = reader.ReadLine();
             entry.PartCount = Int32.Parse(reader.ReadLine());
             entry.FileExtension = reader.ReadLine();
             entry.ReadyParts = new List<Int32>();
    
             while (!reader.EndOfStream)
             {
                 var str = reader.ReadLine();
                 if (String.IsNullOrEmpty(str)) continue;
    
                 entry.ReadyParts.Add(Int32.Parse(str));
             }
    
             reader.Close();
             stream.Close();
             reader.Dispose();
             stream.Dispose();
    
             return entry;
         }
    
         /// <summary>
         /// 写入数据文件
         /// </summary>
         /// <param name="context"></param>
         /// <param name="fileSize"></param>
         /// <param name="filePath"></param>
         private void WriteDataIntoDataFile(HttpContext context, int fileSize, string filePath)
         {
             var fileData = new byte[fileSize];
             context.Request.InputStream.Read(fileData, 0, fileSize);
    
             var stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);
             stream.Position = 0;
             stream.Write(fileData, 0, fileSize);
    
             stream.Flush();
    
             stream.Close();
             stream.Dispose();
         }
    
         /// <summary>
         /// 写入配置文件
         /// </summary>
         /// <param name="configFilePath"></param>
         /// <param name="data"></param>
         private void WriteDataIntoConfigFile(string configFilePath, Object data)
         {
             var stream = new FileStream(configFilePath, FileMode.Append, FileAccess.Write, FileShare.Write);
             var writer = new StreamWriter(stream);
    
             writer.WriteLine(data);
    
             writer.Flush();
             stream.Flush();
    
             writer.Close();
             stream.Close();
             writer.Dispose();
             stream.Dispose();
         }
    
         public bool IsReusable
         {
             get
             {
                 return false;
             }
         }
     }
 }


知识共享许可协议
《.Net 大文件+多线程上传控件(Activex)》常伟华 创作。
采用 知识共享 署名-相同方式共享 3.0 中国大陆 许可协议进行许可。
  • 多说评论
  • 签名
  • 新浪微博
  • 默认评论
  • Tab Header 5

0 条评论 / 点击此处发表评论

Tab Content 5

开发技术


开发平台和工具

sitemap     161.14ms