综合网上多个教程,加上自己实践得出的方法,目前能够兼容谷歌、IE11、IE10。
htmlbody里的内容,没什么特殊的。
1 <div id="dConfirm"> 2 <p style="float: left;margin-left: 20px;margin-top: 20px"> 3 <form action="javascript: uploadAndSubmit();" name="demoForm" id="demoForm" method="post" enctype="multipart/form-data"> 4 <p>上传文件: <input type="file" name="file" id="str_file"/></p> 5 <p><input type="submit" value="上传" /></p> 6 </form> 7 </p> 8 </div>
读取二进制文件:
1 function uploadAndSubmit() 2 { 3 filename=document.getElementById("str_file").value; 4 var form = document.forms["demoForm"]; 5 if(filename!="") 6 { 7 try 8 { 9 var obj = new ActiveXObject("ADODB.Stream");//这个必然是IE 10 } 11 catch(e) 12 { 13 var file = form["file"].files[0]; 14 var reader = new FileReader(); 15 reader.readAsBinaryString(file);//这个读法是异步的 16 17 reader.onloadend=function() 18 { 19 // 这个事件在读取结束后,无论成功或者失败都会触发 20 if (reader.error) { 21 console.log(reader.error); 22 } else { 23 uploadAndSubmit2(reader.result); 24 } 25 } 26 return; 27 } 28 var bf1=new BinaryFile(filename);//这个读法是同步的 29 uploadAndSubmit2(bf1.ReadAll()); 30 } 31 }
这里要对浏览器类型做一下判断,如果不是IE则使用FileReader进行读取,如果是IE则使用activex控件读取。这里有一个坑,虽然IE11和IE10不支持FileReader对象的方法,但IE11和IE10的“typeof FileReader”并不是“undefined”,难以直接通过是否支持FileReader来区分浏览器。还要注意的是FileReader方法是异步读文件,activex是同步读文件,我一直没想明白这两条路线怎样封装在一个方法里,不知大家有没有好办法。
其中BinaryFile对象的构造方法摘自http://www.codeproject.com/Articles/17825/Reading-and-Writing-Binary-Files-Using-JScript?msg=3718403#xx3718403xx技术博客,在博客的回复中有一个改进方法据说效率更高,但因为没有看懂,所以选用了原始方法。
原始方法很长:
1 //使用ADODB.Stream控件时要注意ISO-8859-1和Windows-1252字符集之间的转换 2 function BinaryFile(name) 3 { 4 var adTypeBinary = 1 5 var adTypeText = 2 6 var adSaveCreateOverWrite = 2 7 // The trick - this is the 'old fassioned' not translation page 8 // It lest javascript use strings to act like raw octets 9 var codePage='437'; 10 11 this.path=name; 12 13 var forward = new Array(); 14 var backward = new Array(); 15 16 // Note - for better performance I should preconvert these hex 17 // definitions to decimal - at some point :-) - AJT 18 forward['80'] = '00C7'; 19 forward['81'] = '00FC'; 20 forward['82'] = '00E9'; 21 forward['83'] = '00E2'; 22 forward['84'] = '00E4'; 23 forward['85'] = '00E0'; 24 forward['86'] = '00E5'; 25 forward['87'] = '00E7'; 26 forward['88'] = '00EA'; 27 forward['89'] = '00EB'; 28 forward['8A'] = '00E8'; 29 forward['8B'] = '00EF'; 30 forward['8C'] = '00EE'; 31 forward['8D'] = '00EC'; 32 forward['8E'] = '00C4'; 33 forward['8F'] = '00C5'; 34 forward['90'] = '00C9'; 35 forward['91'] = '00E6'; 36 forward['92'] = '00C6'; 37 forward['93'] = '00F4'; 38 forward['94'] = '00F6'; 39 forward['95'] = '00F2'; 40 forward['96'] = '00FB'; 41 forward['97'] = '00F9'; 42 forward['98'] = '00FF'; 43 forward['99'] = '00D6'; 44 forward['9A'] = '00DC'; 45 forward['9B'] = '00A2'; 46 forward['9C'] = '00A3'; 47 forward['9D'] = '00A5'; 48 forward['9E'] = '20A7'; 49 forward['9F'] = '0192'; 50 forward['A0'] = '00E1'; 51 forward['A1'] = '00ED'; 52 forward['A2'] = '00F3'; 53 forward['A3'] = '00FA'; 54 forward['A4'] = '00F1'; 55 forward['A5'] = '00D1'; 56 forward['A6'] = '00AA'; 57 forward['A7'] = '00BA'; 58 forward['A8'] = '00BF'; 59 forward['A9'] = '2310'; 60 forward['AA'] = '00AC'; 61 forward['AB'] = '00BD'; 62 forward['AC'] = '00BC'; 63 forward['AD'] = '00A1'; 64 forward['AE'] = '00AB'; 65 forward['AF'] = '00BB'; 66 forward['B0'] = '2591'; 67 forward['B1'] = '2592'; 68 forward['B2'] = '2593'; 69 forward['B3'] = '2502'; 70 forward['B4'] = '2524'; 71 forward['B5'] = '2561'; 72 forward['B6'] = '2562'; 73 forward['B7'] = '2556'; 74 forward['B8'] = '2555'; 75 forward['B9'] = '2563'; 76 forward['BA'] = '2551'; 77 forward['BB'] = '2557'; 78 forward['BC'] = '255D'; 79 forward['BD'] = '255C'; 80 forward['BE'] = '255B'; 81 forward['BF'] = '2510'; 82 forward['C0'] = '2514'; 83 forward['C1'] = '2534'; 84 forward['C2'] = '252C'; 85 forward['C3'] = '251C'; 86 forward['C4'] = '2500'; 87 forward['C5'] = '253C'; 88 forward['C6'] = '255E'; 89 forward['C7'] = '255F'; 90 forward['C8'] = '255A'; 91 forward['C9'] = '2554'; 92 forward['CA'] = '2569'; 93 forward['CB'] = '2566'; 94 forward['CC'] = '2560'; 95 forward['CD'] = '2550'; 96 forward['CE'] = '256C'; 97 forward['CF'] = '2567'; 98 forward['D0'] = '2568'; 99 forward['D1'] = '2564'; 100 forward['D2'] = '2565'; 101 forward['D3'] = '2559'; 102 forward['D4'] = '2558'; 103 forward['D5'] = '2552'; 104 forward['D6'] = '2553'; 105 forward['D7'] = '256B'; 106 forward['D8'] = '256A'; 107 forward['D9'] = '2518'; 108 forward['DA'] = '250C'; 109 forward['DB'] = '2588'; 110 forward['DC'] = '2584'; 111 forward['DD'] = '258C'; 112 forward['DE'] = '2590'; 113 forward['DF'] = '2580'; 114 forward['E0'] = '03B1'; 115 forward['E1'] = '00DF'; 116 forward['E2'] = '0393'; 117 forward['E3'] = '03C0'; 118 forward['E4'] = '03A3'; 119 forward['E5'] = '03C3'; 120 forward['E6'] = '00B5'; 121 forward['E7'] = '03C4'; 122 forward['E8'] = '03A6'; 123 forward['E9'] = '0398'; 124 forward['EA'] = '03A9'; 125 forward['EB'] = '03B4'; 126 forward['EC'] = '221E'; 127 forward['ED'] = '03C6'; 128 forward['EE'] = '03B5'; 129 forward['EF'] = '2229'; 130 forward['F0'] = '2261'; 131 forward['F1'] = '00B1'; 132 forward['F2'] = '2265'; 133 forward['F3'] = '2264'; 134 forward['F4'] = '2320'; 135 forward['F5'] = '2321'; 136 forward['F6'] = '00F7'; 137 forward['F7'] = '2248'; 138 forward['F8'] = '00B0'; 139 forward['F9'] = '2219'; 140 forward['FA'] = '00B7'; 141 forward['FB'] = '221A'; 142 forward['FC'] = '207F'; 143 forward['FD'] = '00B2'; 144 forward['FE'] = '25A0'; 145 forward['FF'] = '00A0'; 146 backward['C7'] = '80'; 147 backward['FC'] = '81'; 148 backward['E9'] = '82'; 149 backward['E2'] = '83'; 150 backward['E4'] = '84'; 151 backward['E0'] = '85'; 152 backward['E5'] = '86'; 153 backward['E7'] = '87'; 154 backward['EA'] = '88'; 155 backward['EB'] = '89'; 156 backward['E8'] = '8A'; 157 backward['EF'] = '8B'; 158 backward['EE'] = '8C'; 159 backward['EC'] = '8D'; 160 backward['C4'] = '8E'; 161 backward['C5'] = '8F'; 162 backward['C9'] = '90'; 163 backward['E6'] = '91'; 164 backward['C6'] = '92'; 165 backward['F4'] = '93'; 166 backward['F6'] = '94'; 167 backward['F2'] = '95'; 168 backward['FB'] = '96'; 169 backward['F9'] = '97'; 170 backward['FF'] = '98'; 171 backward['D6'] = '99'; 172 backward['DC'] = '9A'; 173 backward['A2'] = '9B'; 174 backward['A3'] = '9C'; 175 backward['A5'] = '9D'; 176 backward['20A7'] = '9E'; 177 backward['192'] = '9F'; 178 backward['E1'] = 'A0'; 179 backward['ED'] = 'A1'; 180 backward['F3'] = 'A2'; 181 backward['FA'] = 'A3'; 182 backward['F1'] = 'A4'; 183 backward['D1'] = 'A5'; 184 backward['AA'] = 'A6'; 185 backward['BA'] = 'A7'; 186 backward['BF'] = 'A8'; 187 backward['2310'] = 'A9'; 188 backward['AC'] = 'AA'; 189 backward['BD'] = 'AB'; 190 backward['BC'] = 'AC'; 191 backward['A1'] = 'AD'; 192 backward['AB'] = 'AE'; 193 backward['BB'] = 'AF'; 194 backward['2591'] = 'B0'; 195 backward['2592'] = 'B1'; 196 backward['2593'] = 'B2'; 197 backward['2502'] = 'B3'; 198 backward['2524'] = 'B4'; 199 backward['2561'] = 'B5'; 200 backward['2562'] = 'B6'; 201 backward['2556'] = 'B7'; 202 backward['2555'] = 'B8'; 203 backward['2563'] = 'B9'; 204 backward['2551'] = 'BA'; 205 backward['2557'] = 'BB'; 206 backward['255D'] = 'BC'; 207 backward['255C'] = 'BD'; 208 backward['255B'] = 'BE'; 209 backward['2510'] = 'BF'; 210 backward['2514'] = 'C0'; 211 backward['2534'] = 'C1'; 212 backward['252C'] = 'C2'; 213 backward['251C'] = 'C3'; 214 backward['2500'] = 'C4'; 215 backward['253C'] = 'C5'; 216 backward['255E'] = 'C6'; 217 backward['255F'] = 'C7'; 218 backward['255A'] = 'C8'; 219 backward['2554'] = 'C9'; 220 backward['2569'] = 'CA'; 221 backward['2566'] = 'CB'; 222 backward['2560'] = 'CC'; 223 backward['2550'] = 'CD'; 224 backward['256C'] = 'CE'; 225 backward['2567'] = 'CF'; 226 backward['2568'] = 'D0'; 227 backward['2564'] = 'D1'; 228 backward['2565'] = 'D2'; 229 backward['2559'] = 'D3'; 230 backward['2558'] = 'D4'; 231 backward['2552'] = 'D5'; 232 backward['2553'] = 'D6'; 233 backward['256B'] = 'D7'; 234 backward['256A'] = 'D8'; 235 backward['2518'] = 'D9'; 236 backward['250C'] = 'DA'; 237 backward['2588'] = 'DB'; 238 backward['2584'] = 'DC'; 239 backward['258C'] = 'DD'; 240 backward['2590'] = 'DE'; 241 backward['2580'] = 'DF'; 242 backward['3B1'] = 'E0'; 243 backward['DF'] = 'E1'; 244 backward['393'] = 'E2'; 245 backward['3C0'] = 'E3'; 246 backward['3A3'] = 'E4'; 247 backward['3C3'] = 'E5'; 248 backward['B5'] = 'E6'; 249 backward['3C4'] = 'E7'; 250 backward['3A6'] = 'E8'; 251 backward['398'] = 'E9'; 252 backward['3A9'] = 'EA'; 253 backward['3B4'] = 'EB'; 254 backward['221E'] = 'EC'; 255 backward['3C6'] = 'ED'; 256 backward['3B5'] = 'EE'; 257 backward['2229'] = 'EF'; 258 backward['2261'] = 'F0'; 259 backward['B1'] = 'F1'; 260 backward['2265'] = 'F2'; 261 backward['2264'] = 'F3'; 262 backward['2320'] = 'F4'; 263 backward['2321'] = 'F5'; 264 backward['F7'] = 'F6'; 265 backward['2248'] = 'F7'; 266 backward['B0'] = 'F8'; 267 backward['2219'] = 'F9'; 268 backward['B7'] = 'FA'; 269 backward['221A'] = 'FB'; 270 backward['207F'] = 'FC'; 271 backward['B2'] = 'FD'; 272 backward['25A0'] = 'FE'; 273 backward['A0'] = 'FF'; 274 275 var hD="0123456789ABCDEF"; 276 this.d2h = function(d) 277 { 278 var h = hD.substr(d&15,1); 279 while(d>15) {d>>=4;h=hD.substr(d&15,1)+h;} 280 return h; 281 } 282 283 this.h2d = function(h) 284 { 285 return parseInt(h,16); 286 } 287 288 this.WriteAll = function(what) 289 { 290 //Create Stream object 291 //var BinaryStream = WScript.CreateObject("ADODB.Stream"); 292 var BinaryStream = new ActiveXObject("ADODB.Stream"); 293 //Specify stream type - we cheat and get string but 'like' binary 294 BinaryStream.Type = adTypeText; 295 BinaryStream.CharSet = '437'; 296 //Open the stream 297 BinaryStream.Open(); 298 // Write to the stream 299 BinaryStream.WriteText(this.Forward437(what)); 300 // Write the string to the disk 301 BinaryStream.SaveToFile(this.path, adSaveCreateOverWrite); 302 303 // Clearn up 304 BinaryStream.Close(); 305 } 306 307 this.ReadAll = function() 308 { 309 //Create Stream object - needs ADO 2.5 or heigher 310 //var BinaryStream = WScript.CreateObject("ADODB.Stream") 311 var BinaryStream = new ActiveXObject("ADODB.Stream"); 312 //Specify stream type - we cheat and get string but 'like' binary 313 BinaryStream.Type = adTypeText; 314 BinaryStream.CharSet = codePage; 315 //Open the stream 316 BinaryStream.Open(); 317 //Load the file data from disk To stream object 318 BinaryStream.LoadFromFile(this.path); 319 //Open the stream And get binary 'string' from the object 320 var what = BinaryStream.ReadText; 321 // Clean up 322 BinaryStream.Close(); 323 return this.Backward437(what); 324 } 325 326 /* Convert a octet number to a code page 437 char code */ 327 this.Forward437 = function(inString) 328 { 329 var encArray = new Array(); 330 var tmp=''; 331 var i=0; 332 var c=0; 333 var l=inString.length; 334 var cc; 335 var h; 336 for(;i<l;++i) 337 { 338 c++; 339 if(c==128) 340 { 341 encArray.push(tmp); 342 tmp=''; 343 c=0; 344 } 345 cc=inString.charCodeAt(i); 346 if(cc<128) 347 { 348 tmp+=String.fromCharCode(cc); 349 } 350 else 351 { 352 h=this.d2h(cc); 353 h=forward[''+h]; 354 tmp+=String.fromCharCode(this.h2d(h)); 355 } 356 } 357 if(tmp!='') 358 { 359 encArray.push(tmp); 360 } 361 362 // this loop progressive concatonates the 363 // array elements entil there is only one 364 var ar2=new Array(); 365 for(;encArray.length>1;) 366 { 367 var l=encArray.length; 368 for(var c=0;c<l;c+=2) 369 { 370 if(c+1==l) 371 { 372 ar2.push(encArray[c]); 373 } 374 else 375 { 376 ar2.push(''+encArray[c]+encArray[c+1]); 377 } 378 } 379 encArray=ar2; 380 ar2=new Array(); 381 } 382 return encArray[0]; 383 } 384 /* Convert a code page 437 char code to a octet number*/ 385 this.Backward437 = function(inString) 386 { 387 var encArray = new Array(); 388 var tmp=''; 389 var i=0; 390 var c=0; 391 var l=inString.length; 392 var cc; 393 var h; 394 for(;i<l;++i) 395 { 396 c++; 397 if(c==128) 398 { 399 encArray.push(tmp); 400 tmp=''; 401 c=0; 402 } 403 cc=inString.charCodeAt(i); 404 if(cc<128) 405 { 406 tmp+=String.fromCharCode(cc); 407 } 408 else 409 { 410 h=this.d2h(cc); 411 h=backward[''+h]; 412 tmp+=String.fromCharCode(this.h2d(h)); 413 } 414 } 415 if(tmp!='') 416 { 417 encArray.push(tmp); 418 } 419 420 // this loop progressive concatonates the 421 // array elements entil there is only one 422 var ar2=new Array(); 423 for(;encArray.length>1;) 424 { 425 var l=encArray.length; 426 for(var c=0;c<l;c+=2) 427 { 428 if(c+1==l) 429 { 430 ar2.push(encArray[c]); 431 } 432 else 433 { 434 ar2.push(''+encArray[c]+encArray[c+1]); 435 } 436 } 437 encArray=ar2; 438 ar2=new Array(); 439 } 440 return encArray[0]; 441 } 442 }
其中主体部分是:
1 this.ReadAll = function() 2 { 3 //Create Stream object - needs ADO 2.5 or heigher 4 //var BinaryStream = WScript.CreateObject("ADODB.Stream") 5 var BinaryStream = new ActiveXObject("ADODB.Stream"); 6 //Specify stream type - we cheat and get string but 'like' binary 7 BinaryStream.Type = adTypeText; 8 BinaryStream.CharSet = codePage; 9 //Open the stream 10 BinaryStream.Open(); 11 //Load the file data from disk To stream object 12 BinaryStream.LoadFromFile(this.path); 13 //Open the stream And get binary 'string' from the object 14 var what = BinaryStream.ReadText; 15 // Clean up 16 BinaryStream.Close(); 17 return this.Backward437(what); 18 }
这里就是使用"ADODB.Stream"控件读取文件的方法,可以看到作者使用的读取类型是adTypeText(2),是在用文本读取方式读二进制文件!而按照文档改为adTypeBinary(1)类型后则读不到任何内容,不知道是为什么。
其余部分代码则是在做编码转换工作,大体意思是读文件时要使用“ISO-8859-1”字符集,用http发送文件时则要使用“Windows-1252”字符集,这两种字符集只有极少数字符有差别,所以在读到的数据中找到有区别的部分一一转换为另一种字符集表示。
ajax发送二进制流:
1 function uploadAndSubmit2(BinaryContent) 2 { 3 Url = UrlHead + "Cook.ashx"; 4 xmlHttp=new XMLHttpRequest(); 5 xmlHttp.open("POST",Url + "?method=post&func=file_upload&fileName=" + encodeURIComponent(filename.split("\")[filename.split("\").length-1]));//IE处理汉字url 6 xmlHttp.sendAsBinary(BinaryContent); 7 xmlHttp.onreadystatechange = function () 8 { 9 if (xmlHttp.readyState == 4) { 10 if (xmlHttp.status == 200) { 11 var str=xmlHttp.response; 12 alert(str); 13 xmlHttp.abort(); 14 } 15 } 16 } 17 }
为了进行二进制传输这里没有使用兼容旧版本IE的“window.ActiveXObject("Msxm12.XMLHTTP")”和“window.ActiveXObject("Microsoft.XMLHTTP")”,不知大家有没有支持这两种activex控件的二进制传输方法。
在一篇教程里第六行前面有一行:
xmlHttp.overrideMimeType('text/plain; charset=x-user-defined');//:x-user-defined告诉浏览器不要解析返回数据
加上这个一行后浏览器将不会对后台返回的数据的编码格式进行解析,具体来讲就是返回到前台的中文文本都显示为“ ”或“口”,我估计作者这样做是为了在前台接收后台传来的二进制数据。
事实上只有火狐的XMLHttpRequest支持sendAsBinary方法,为了在IE和谷歌下使用,需要给XMLHttpRequest增加一个原型方法:
1 //给XMLHttpRequest的原型添加二进制发送功能 2 XMLHttpRequest.prototype.sendAsBinary = function(datastr) { 3 function byteValue(x) { 4 return x.charCodeAt(0) & 0xff; 5 } 6 var ords = Array.prototype.map.call(datastr, byteValue); 7 var ui8a = new Uint8Array(ords); 8 this.send(ui8a.buffer); 9 }
这里的代码就不太懂了,其中第六行IE8不支持、第七行IE9不支持。
后台使用的是java serverlet,以下是最终调用的java类的代码:
1 public String FileUpload(HttpServletRequest request) throws IOException 2 { 3 request.setCharacterEncoding("UTF-8"); 4 BufferedInputStream fileIn = new BufferedInputStream(request.getInputStream()); 5 String fn = request.getParameter("fileName"); 6 byte[] buf = new byte[1024]; 7 File file = new File("d:/" + fn); 8 BufferedOutputStream fileOut = new BufferedOutputStream(new FileOutputStream(file)); 9 try 10 { 11 while (true) 12 { 13 // 读取数据 14 int bytesIn = fileIn.read(buf, 0, 1024); 15 System.out.println(bytesIn); 16 if (bytesIn == -1) 17 { 18 break; 19 } 20 else 21 { 22 fileOut.write(buf, 0, bytesIn); 23 } 24 } 25 fileOut.flush(); 26 return("保存成功"); 27 } 28 catch(Exception e) 29 { 30 return "保存失败,原因:"+e.toString(); 31 } 32 finally 33 { 34 fileOut.close(); 35 } 36 }