2010-06-30 42 views
24

Tôi hiện đang làm việc trên API tệp HTML5 và tôi cần nhận dữ liệu tệp nhị phân. Các phương thức The FileReader 's readAsTextreadAsDataURL hoạt động tốt, nhưng readAsBinaryString trả lại cùng một dữ liệu là readAsText.API tệp HTML5 được đọc dưới dạng văn bản và nhị phân

Tôi cần dữ liệu nhị phân, nhưng tôi nhận được chuỗi văn bản. Tui bỏ lỡ điều gì vậy?

Trả lời

66

readAsBinaryString nói rằng dữ liệu phải được thể hiện dưới dạng một binary string, trong đó:

... mỗi byte được đại diện bởi một số nguyên trong khoảng [0..255].

Javascript ban đầu đã không có một "nhị phân" loại (cho đến hỗ trợ WebGL ECMAScript 5 của Typed Array * (xem chi tiết bên dưới) - nó đã được thay thế bởi ECMAScript 2015 của ArrayBuffer) và vì vậy họ đã đi với một String với sự đảm bảo rằng không có ký tự nào được lưu trữ trong String sẽ nằm ngoài phạm vi 0..255. (Họ có thể đã đi với một mảng số thay vào đó, nhưng họ không, có lẽ các chuỗi lớn có nhiều bộ nhớ hiệu quả hơn các mảng lớn của số, vì số là dấu phẩy động.)

Nếu bạn đang đọc tập tin đó chủ yếu là văn bản trong một kịch bản phương Tây (chủ yếu là tiếng Anh, ví dụ), sau đó chuỗi đó sẽ tìm một như văn bản. Nếu bạn đọc một tệp có các ký tự Unicode trong đó, bạn sẽ thấy một sự khác biệt, vì chuỗi JavaScript là UTF-16 ** (chi tiết bên dưới) và do đó một số ký tự sẽ có giá trị trên 255, trong khi "chuỗi nhị phân" theo Tệp Thông số API sẽ không có bất kỳ giá trị nào trên 255 (bạn có hai ký tự "riêng lẻ" cho hai byte của điểm mã Unicode).

Nếu bạn đang đọc một tập tin đó không phải là văn bản ở tất cả (một hình ảnh, có lẽ), bạn sẽ có thể vẫn nhận được một kết quả rất giống nhau giữa readAsTextreadAsBinaryString, nhưng với readAsBinaryString bạn biết rằng có sẽ không là bất kỳ nỗ lực nào để diễn giải các chuỗi đa byte dưới dạng ký tự. Bạn không biết rằng nếu bạn sử dụng readAsText, vì readAsText sẽ sử dụng encoding determination để tìm hiểu xem mã hóa của tệp là gì và sau đó ánh xạ nó tới chuỗi UTF-16 của JavaScript.

Bạn có thể thấy hiệu ứng nếu bạn tạo tệp và lưu trữ tệp đó trong một tệp khác ngoài ASCII hoặc UTF-8. (Trong Windows, bạn có thể thực hiện điều này thông qua Notepad; "Lưu dưới dạng" dưới dạng bảng mã thả xuống với "Unicode" trên đó, bằng cách xem dữ liệu có vẻ như UTF-16; Tôi chắc chắn là Mac OS và * nix biên tập có một tính năng tương tự) Dưới đây là một trang mà bãi kết quả của việc đọc một tập tin cả hai cách:.

<!DOCTYPE HTML> 
<html> 
<head> 
<meta http-equiv="Content-type" content="text/html;charset=UTF-8"> 
<title>Show File Data</title> 
<style type='text/css'> 
body { 
    font-family: sans-serif; 
} 
</style> 
<script type='text/javascript'> 

    function loadFile() { 
     var input, file, fr; 

     if (typeof window.FileReader !== 'function') { 
      bodyAppend("p", "The file API isn't supported on this browser yet."); 
      return; 
     } 

     input = document.getElementById('fileinput'); 
     if (!input) { 
      bodyAppend("p", "Um, couldn't find the fileinput element."); 
     } 
     else if (!input.files) { 
      bodyAppend("p", "This browser doesn't seem to support the `files` property of file inputs."); 
     } 
     else if (!input.files[0]) { 
      bodyAppend("p", "Please select a file before clicking 'Load'"); 
     } 
     else { 
      file = input.files[0]; 
      fr = new FileReader(); 
      fr.onload = receivedText; 
      fr.readAsText(file); 
     } 

     function receivedText() { 
      showResult(fr, "Text"); 

      fr = new FileReader(); 
      fr.onload = receivedBinary; 
      fr.readAsBinaryString(file); 
     } 

     function receivedBinary() { 
      showResult(fr, "Binary"); 
     } 
    } 

    function showResult(fr, label) { 
     var markup, result, n, aByte, byteStr; 

     markup = []; 
     result = fr.result; 
     for (n = 0; n < result.length; ++n) { 
      aByte = result.charCodeAt(n); 
      byteStr = aByte.toString(16); 
      if (byteStr.length < 2) { 
       byteStr = "0" + byteStr; 
      } 
      markup.push(byteStr); 
     } 
     bodyAppend("p", label + " (" + result.length + "):"); 
     bodyAppend("pre", markup.join(" ")); 
    } 

    function bodyAppend(tagName, innerHTML) { 
     var elm; 

     elm = document.createElement(tagName); 
     elm.innerHTML = innerHTML; 
     document.body.appendChild(elm); 
    } 

</script> 
</head> 
<body> 
<form action='#' onsubmit="return false;"> 
<input type='file' id='fileinput'> 
<input type='button' id='btnLoad' value='Load' onclick='loadFile();'> 
</form> 
</body> 
</html> 

Nếu tôi sử dụng điều đó với một tập tin "Kiểm tra 1 2 3" được lưu trữ dưới dạng UTF-16, đây là kết quả tôi nhận được:

Text (13): 

54 65 73 74 69 6e 67 20 31 20 32 20 33 

Binary (28): 

ff fe 54 00 65 00 73 00 74 00 69 00 6e 00 67 00 20 00 31 00 20 00 32 00 20 00 33 00

Như bạn thấy, readAsText giải thích các nhân vật và vì thế tôi đã 13 (chiều dài của "thử nghiệm 1 2 3"), và readAsBinaryString không, và vì vậy tôi đã 28 (hai byte BOM cộng với hai byte cho mỗi ký tự).


* XMLHttpRequest.response với responseType = "arraybuffer" được hỗ trợ trong HTML 5.

** "Chuỗi JavaScript là UTF-16" có vẻ giống như một câu lệnh kỳ lạ; không phải họ chỉ là Unicode? Không, chuỗi JavaScript là a series of UTF-16 code units; bạn thấy cặp thay thế là hai "ký tự" JavaScript cá nhân mặc dù, trên thực tế, cặp thay thế nói chung chỉ là một ký tự. Xem liên kết để biết chi tiết.

+0

Vì vậy, nó trả về văn bản được mã hóa từ 0-255? Có cách nào để chuyển đổi các ký tự đó thành dữ liệu nhị phân hoặc hex (0-1 hoặc 0-FF) không? – tcooc

+1

@digitalFresh: Chuỗi * là * dữ liệu nhị phân. Như bạn đã bình luận, tôi đã đăng một ví dụ có thể hữu ích. JavaScript không có kiểu "nhị phân" và vì vậy chúng đã đi với một Chuỗi có bảo đảm rằng không có ký tự nào được lưu trữ trong chuỗi sẽ nằm ngoài phạm vi 0..255. (Họ có thể đã đi với một loạt các con số thay vào đó, nhưng họ không.) Ví dụ cho thấy làm thế nào để có được giá trị thô của một "nhân vật" từ chuỗi. –

+0

Tôi đã thử mã này với Chrome 7.0. Gọi lại không bao giờ được gọi. Đồng thời, không có lỗi trong cửa sổ gỡ lỗi. Bất kỳ giúp đỡ? – morpheus

Các vấn đề liên quan