你的位置:首页 > Java教程

[Java教程]JavaScript读二进制文件并用ajax传输二进制流


综合网上多个教程,加上自己实践得出的方法,目前能够兼容谷歌、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>

View Code

读取二进制文件:

 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");//这个必然是IE10       }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 object291     //var BinaryStream = WScript.CreateObject("ADODB.Stream");292     var BinaryStream = new ActiveXObject("ADODB.Stream");293     //Specify stream type - we cheat and get string but 'like' binary294     BinaryStream.Type = adTypeText;295     BinaryStream.CharSet = '437';296     //Open the stream297     BinaryStream.Open();298     // Write to the stream299     BinaryStream.WriteText(this.Forward437(what));300     // Write the string to the disk301     BinaryStream.SaveToFile(this.path, adSaveCreateOverWrite);302 303     // Clearn up304     BinaryStream.Close();305   }306 307   this.ReadAll = function()308   {309     //Create Stream object - needs ADO 2.5 or heigher310     //var BinaryStream = WScript.CreateObject("ADODB.Stream")311     var BinaryStream = new ActiveXObject("ADODB.Stream");312     //Specify stream type - we cheat and get string but 'like' binary313     BinaryStream.Type = adTypeText;314     BinaryStream.CharSet = codePage;315     //Open the stream316     BinaryStream.Open();317     //Load the file data from disk To stream object318     BinaryStream.LoadFromFile(this.path);319     //Open the stream And get binary 'string' from the object320     var what = BinaryStream.ReadText;321     // Clean up322     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       else351       {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 the363     // array elements entil there is only one364     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         else375         {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       else409       {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 the421     // array elements entil there is only one422     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         else433         {434           ar2.push(''+encArray[c]+encArray[c+1]);435         }436       }437       encArray=ar2;438       ar2=new Array();439     }440     return encArray[0];441   }442 }

View Code

其中主体部分是:

 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 stream10     BinaryStream.Open();11     //Load the file data from disk To stream object12     BinaryStream.LoadFromFile(this.path);13     //Open the stream And get binary 'string' from the object14     var what = BinaryStream.ReadText;15     // Clean up16     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     new  5     //IE处理汉字url 6      7     function () 8     { 9       if () {10         if () {11           var str=12           alert(str);13           14         }15       }16     }17   }

为了进行二进制传输这里没有使用兼容旧版本IE的“window.ActiveXObject("Msxm12.

在一篇教程里第六行前面有一行:

//:x-user-defined告诉浏览器不要解析返回数据

加上这个一行后浏览器将不会对后台返回的数据的编码格式进行解析,具体来讲就是返回到前台的中文文本都显示为“ ”或“口”,我估计作者这样做是为了在前台接收后台传来的二进制数据。

 

事实上只有火狐的

1 //给2 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     try10     {      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     finally33     {      34       fileOut.close(); 35     }36   }