之前项目中碰到,IIS上传大文件报错的问题,查了下是iis的设置问题,改吧改吧就好了,总感觉不爽,就自己写了一个大文件上传的activex,无奈,本人只有.net做的好点,就用.net写了一个,当然了,主要用的还是C#。
怎么编写activex网上有很多,大家百度下,谷歌下,都出来了。
我就把代码发出来,有要的可以研究下,注释什么的,还是很规范的。
Activex部分:
UploadActivexCtrl
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Globalization; 7 using System.IO; 8 using System.Linq; 9 using System.Net; 10 using System.Runtime.InteropServices; 11 using System.Text; 12 using System.Threading; 13 using System.Threading.Tasks; 14 using System.Web; 15 using System.Windows.Forms; 16 17 namespace MutifileUploadCtrl 18 { 19 [ComVisible(true)] 20 [Guid("C4F9F24F-B860-4e79-945D-B9A281950C82")] 21 [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] 22 public interface IUploadControlComEvents 23 { 24 [DispId(0x10000002)] 25 void OnUploaded(); 26 [DispId(0x10000003)] 27 void OnStatusChanged(String status); 28 } 29 // 30 // [Guid("4B3AE7D8-FB6A-4558-8A96-BF82B54F329C")] 31 // [ComVisible(true)] 32 // public interface IUploadControlComOjbect 33 // { 34 // [DispId(0x10000001)] 35 // void Upload(String filePaths, String saveFileNames); 36 // } 37 38 [Guid("6e60ddbf-84fa-4d8f-b479-60879c861686"), 39 ComSourceInterfaces(typeof(IUploadControlComEvents)), 40 ClassInterface(ClassInterfaceType.AutoDual), 41 // ComDefaultInterface(typeof(IUploadControlComOjbect)), 42 // ClassInterface(ClassInterfaceType.None), 43 ComVisible(true)] 44 public class UploadControl : UserControl, IObjectSafety 45 { 46 [ComVisible(true)] 47 public String SvrAddr { get; set; } 48 49 [ComVisible(true)] 50 public delegate void OnUploadedEventHanlder(); 51 public event OnUploadedEventHanlder OnUploaded; 52 53 [ComVisible(true)] 54 public delegate void OnStatusChangedEventHanlder(String status); 55 public event OnStatusChangedEventHanlder OnStatusChanged; 56 57 // 每次上传1M 58 private const Int32 BUFFER_SIZE = 1024 * 1024; 59 60 [ComVisible(true)] 61 public void Upload(String filePaths, String saveFileNames) 62 { 63 var paths = filePaths.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries); 64 var fileNames = saveFileNames.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); 65 66 var factory = new TaskFactory(); 67 68 factory.StartNew(() => 69 { 70 var tasks = new List<Task>(); 71 72 for (int index = 0; index < paths.Length; index++) 73 { 74 var path = paths[index]; 75 var fileName = fileNames[index]; 76 tasks.Add(factory.StartNew(() => UploadFile(path, fileName))); 77 //UploadFile(path, fileName); 78 } 79 80 Task.WaitAll(tasks.ToArray()); 81 82 if (OnUploaded != null) 83 { 84 OnUploaded(); 85 } 86 }); 87 } 88 89 [ComVisible(false)] 90 private void UploadFile(String filePath, String saveFileName) 91 { 92 var fileName = Path.GetFileName(filePath); 93 94 var stream = new FileStream(filePath, FileMode.Open); 95 96 var fileData = new Byte[BUFFER_SIZE]; 97 98 var offset = 0; 99 100 var fileId = Guid.NewGuid().ToString(); 101 102 var totalSize = stream.Length; 103 var partCount = totalSize%BUFFER_SIZE == 0 ? totalSize/BUFFER_SIZE : totalSize/BUFFER_SIZE + 1; 104 105 // 将文件流转写入网络流 106 var part = 1; 107 var response = ""; 108 do 109 { 110 var position = stream.Position; 111 112 offset = stream.Read(fileData, 0, fileData.Length); 113 114 if(offset == 0) break; 115 116 response = PostData(fileData, fileId, saveFileName, position, offset, part, (Int32)partCount); 117 118 if (OnStatusChanged != null) 119 { 120 OnStatusChanged(fileName + ";" + totalSize + ";" + position + ";" + offset); 121 } 122 123 part++; 124 } while (offset > 0 && response == "ok"); 125 126 stream.Close(); 127 stream.Dispose(); 128 } 129 130 [ComVisible(false)] 131 private String PostData(byte[] data, String fileId, String fileName, long position, Int32 size, Int32 part, Int32 partCount) 132 { 133 if (String.IsNullOrEmpty(SvrAddr)) return ""; 134 135 var paras = "?FileId=" + HttpUtility.UrlEncode(fileId) + 136 "&PartNum=" + part + 137 "&Position=" + position + 138 "&FileSize=" + size + 139 "&FileName=" + HttpUtility.UrlEncode(fileName) + 140 "&PartCount=" + partCount; 141 142 var request = (HttpWebRequest)WebRequest.Create(SvrAddr + paras); 143 request.Method = "POST"; 144 request.ContentLength = data.Length; 145 146 using (var stream = request.GetRequestStream()) 147 { 148 stream.Write(data, 0, data.Length); 149 stream.Close(); 150 } 151 152 using (var myResponse = (HttpWebResponse) request.GetResponse()) 153 { 154 var reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8); 155 return reader.ReadToEnd(); 156 } 157 } 158 159 #region 实现IObjectSafety接口 160 private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}"; 161 private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}"; 162 private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}"; 163 private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}"; 164 private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}"; 165 166 private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001; 167 private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002; 168 private const int S_OK = 0; 169 private const int E_FAIL = unchecked((int)0x80004005); 170 private const int E_NOINTERFACE = unchecked((int)0x80004002); 171 172 private bool _fSafeForScripting = true; 173 private bool _fSafeForInitializing = true; 174 //使ActiveX控件成为安全的控件 175 public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions) 176 { 177 int Rslt = E_FAIL; 178 string strGUID = riid.ToString("B"); 179 pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA; 180 switch (strGUID) 181 { 182 case _IID_IDispatch: 183 case _IID_IDispatchEx: 184 Rslt = S_OK; 185 pdwEnabledOptions = 0; 186 if (_fSafeForScripting == true) 187 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER; 188 break; 189 case _IID_IPersistStorage: 190 case _IID_IPersistStream: 191 case _IID_IPersistPropertyBag: 192 Rslt = S_OK; 193 pdwEnabledOptions = 0; 194 if (_fSafeForInitializing == true) 195 pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA; 196 break; 197 default: 198 Rslt = E_NOINTERFACE; 199 break; 200 } 201 202 return Rslt; 203 } 204 205 public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions) 206 { 207 int Rslt = E_FAIL; 208 209 string strGUID = riid.ToString("B"); 210 switch (strGUID) 211 { 212 case _IID_IDispatch: 213 case _IID_IDispatchEx: 214 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true)) 215 Rslt = S_OK; 216 break; 217 case _IID_IPersistStorage: 218 case _IID_IPersistStream: 219 case _IID_IPersistPropertyBag: 220 if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true)) 221 Rslt = S_OK; 222 break; 223 default: 224 Rslt = E_NOINTERFACE; 225 break; 226 } 227 228 return Rslt; 229 } 230 #endregion 231 } 232 233 [Guid("CB5BDC81-93C1-11CF-8F20-00805F2CD064"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 234 public interface IObjectSafety 235 { 236 [PreserveSig] 237 int GetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] ref int pdwSupportedOptions, [MarshalAs(UnmanagedType.U4)] ref int pdwEnabledOptions); 238 239 [PreserveSig] 240 int SetInterfaceSafetyOptions(ref Guid riid, [MarshalAs(UnmanagedType.U4)] int dwOptionSetMask, 241 [MarshalAs(UnmanagedType.U4)] int dwEnabledOptions); 242 } 243 244 }
后来处理部分:
UploadHandler
1 using System; 2 using System.Collections.Generic; 3 using System.IO; 4 using System.Linq; 5 using System.Threading; 6 using System.Web; 7 8 namespace Server 9 { 10 public class ConfigFileEntry 11 { 12 public String FileId { get; set; } 13 public String FileNameWithoutExtension { get; set; } 14 public Int32 PartCount { get; set; } 15 public String FileExtension { get; set; } 16 public List<Int32> ReadyParts { get; set; } 17 } 18 19 /// <summary> 20 /// Upload 的摘要说明 21 /// </summary> 22 public class Upload : IHttpHandler 23 { 24 private static Boolean _sign = false; 25 const String CONFIG_FILE_EXTENSION = ".conf"; 26 private static String BASE_PATH; 27 public void ProcessRequest(HttpContext context) 28 { 29 BASE_PATH = context.Server.MapPath("~/uploadfiles/"); 30 31 context.Response.ContentType = "text/plain"; 32 context.Response.HeaderEncoding = System.Text.Encoding.UTF8; 33 context.Response.Charset = "utf-8"; 34 35 var fileId = HttpUtility.UrlDecode(context.Request["FileId"]); 36 var fileName = HttpUtility.UrlDecode(context.Request["FileName"]); 37 var position = int.Parse(context.Request["Position"]); 38 var fileSize = int.Parse(context.Request["FileSize"]); 39 var partNum = int.Parse(context.Request["PartNum"]); 40 var fileExtension = Path.GetExtension(fileName); 41 var partCount = int.Parse(context.Request["PartCount"]); 42 var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName); 43 var configFilePath = Path.Combine(BASE_PATH, fileNameWithoutExtension + CONFIG_FILE_EXTENSION); 44 45 // 写入配置文件 46 if (!File.Exists(configFilePath)) 47 { 48 WriteDataIntoConfigFile(configFilePath, fileId); 49 WriteDataIntoConfigFile(configFilePath, fileNameWithoutExtension); 50 WriteDataIntoConfigFile(configFilePath, partCount); 51 WriteDataIntoConfigFile(configFilePath, fileExtension); 52 } 53 54 var filePath = Path.Combine(BASE_PATH, fileNameWithoutExtension + "_" + partNum); 55 56 WriteDataIntoDataFile(context, fileSize, filePath); 57 58 // 启用检查线程,检测文件所有部分是否上传完成 59 if (!_sign) 60 { 61 _sign = true; 62 var thread = new Thread(MergeFile); 63 thread.Start(); 64 } 65 66 // 判断写入文件大小是否等于上传大小 67 var fileInfo = new FileInfo(filePath); 68 69 if (fileInfo.Length == fileSize) 70 { 71 // 把当前结果写入配置文件(表示当前part操作完成) 72 WriteDataIntoConfigFile(configFilePath, partNum); 73 } 74 75 context.Response.Write("ok"); 76 } 77 78 /// <summary> 79 /// 合并文件 80 /// </summary> 81 private void MergeFile() 82 { 83 do 84 { 85 if (!_sign) break; 86 // 获取所有的配置文件 87 var configFiles = Directory.GetFiles(BASE_PATH, "*" + CONFIG_FILE_EXTENSION + "*"); 88 89 foreach (var configFile in configFiles) 90 { 91 var fileName = Path.GetFileNameWithoutExtension(configFile); 92 var tempPath = Path.Combine(BASE_PATH, fileName + ".tmp"); 93 // 移动文件 94 File.Copy(configFile, tempPath, true); 95 96 // 读取配置文件 97 var entry = ReadConfigFile(tempPath); 98 // 全部文件写入完成 99 if (entry.ReadyParts.Count == entry.PartCount) 100 { 101 // 删除配置文件 102 File.Delete(configFile); 103 // 合并文件 104 CombineFiles(entry.FileNameWithoutExtension, entry.FileExtension, entry.ReadyParts); 105 106 // 删除临时文件 107 File.Delete(tempPath); 108 } 109 } 110 111 Thread.Sleep(5000); 112 } while (true); 113 114 115 _sign = true; 116 } 117 118 /// <summary> 119 /// 合并文件 120 /// </summary> 121 /// <param name="fileName"></param> 122 /// <param name="fileExtension"></param> 123 /// <param name="parts"></param> 124 private void CombineFiles(String fileName, String fileExtension, List<Int32> parts) 125 { 126 var stream = new FileStream(Path.Combine(BASE_PATH, fileName + fileExtension), FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write); 127 128 for (var index = 1; index <= parts.Count; index ++) 129 { 130 var dataFilePath = Path.Combine(BASE_PATH, fileName + "_" + index); 131 var position = (Int32)stream.Length; 132 var buffer = File.ReadAllBytes(dataFilePath); 133 stream.Write(buffer, 0, buffer.Length); 134 135 File.Delete(dataFilePath); 136 } 137 138 stream.Flush(); 139 stream.Close(); 140 } 141 142 /// <summary> 143 /// 读取配置文件 144 /// </summary> 145 /// <param name="tempPath"></param> 146 /// <returns></returns> 147 private ConfigFileEntry ReadConfigFile(String tempPath) 148 { 149 var stream = new FileStream(tempPath, FileMode.Open, FileAccess.Read, FileShare.Read); 150 var reader = new StreamReader(stream); 151 152 var entry = new ConfigFileEntry(); 153 154 entry.FileId = reader.ReadLine(); 155 entry.FileNameWithoutExtension = reader.ReadLine(); 156 entry.PartCount = Int32.Parse(reader.ReadLine()); 157 entry.FileExtension = reader.ReadLine(); 158 entry.ReadyParts = new List<Int32>(); 159 160 while (!reader.EndOfStream) 161 { 162 var str = reader.ReadLine(); 163 if (String.IsNullOrEmpty(str)) continue; 164 165 entry.ReadyParts.Add(Int32.Parse(str)); 166 } 167 168 reader.Close(); 169 stream.Close(); 170 reader.Dispose(); 171 stream.Dispose(); 172 173 return entry; 174 } 175 176 /// <summary> 177 /// 写入数据文件 178 /// </summary> 179 /// <param name="context"></param> 180 /// <param name="fileSize"></param> 181 /// <param name="filePath"></param> 182 private void WriteDataIntoDataFile(HttpContext context, int fileSize, string filePath) 183 { 184 var fileData = new byte[fileSize]; 185 context.Request.InputStream.Read(fileData, 0, fileSize); 186 187 var stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write); 188 stream.Position = 0; 189 stream.Write(fileData, 0, fileSize); 190 191 stream.Flush(); 192 193 stream.Close(); 194 stream.Dispose(); 195 } 196 197 /// <summary> 198 /// 写入配置文件 199 /// </summary> 200 /// <param name="configFilePath"></param> 201 /// <param name="data"></param> 202 private void WriteDataIntoConfigFile(string configFilePath, Object data) 203 { 204 var stream = new FileStream(configFilePath, FileMode.Append, FileAccess.Write, FileShare.Write); 205 var writer = new StreamWriter(stream); 206 207 writer.WriteLine(data); 208 209 writer.Flush(); 210 stream.Flush(); 211 212 writer.Close(); 213 stream.Close(); 214 writer.Dispose(); 215 stream.Dispose(); 216 } 217 218 public bool IsReusable 219 { 220 get 221 { 222 return false; 223 } 224 } 225 } 226 }
下载地址:百度网盘