Je travaille actuellement sur l'API de fichiers HTML5 et j'ai besoin d'obtenir des données de fichiers binaires. Les méthodes readAsText
et readAsDataURL
de The FileReader
Fonctionnent correctement, mais readAsBinaryString
renvoie les mêmes données que readAsText
.
J'ai besoin de données binaires, mais je reçois une chaîne de texte. Suis-je en train de manquer quelque chose?
Remarque en 2018 : readAsBinaryString
est obsolète. Pour les cas d'utilisation où vous l'auriez précédemment utilisé, vous utiliseriez ces jours-ci readAsArrayBuffer
(ou dans certains cas, readAsDataURL
) au lieu.
readAsBinaryString
dit que les données doivent être représentées sous la forme d'une chaîne binaire , où:
... chaque octet est représenté par un entier dans la plage [0..255].
JavaScript à l'origine n'avait pas de type "binaire" (jusqu'à ce que le support WebGL d'ECMAScript 5 Typed Array * (détails ci-dessous) - il a été remplacé par ECMAScript 2015 ArrayBuffer ) et donc ils sont allés avec une chaîne avec la garantie qu'aucun caractère stocké dans la chaîne ne serait en dehors de la plage 0..255. (Ils auraient pu aller avec un tableau de nombres à la place, mais ils ne l'ont pas fait; peut-être que les grandes chaînes sont plus efficaces en mémoire que les grands tableaux de nombres, car les nombres sont à virgule flottante.)
Si vous lisez un fichier qui est principalement du texte dans un script occidental (principalement en anglais, par exemple), alors cette chaîne va ressembler à un texte beaucoup. Si vous lisez un fichier contenant des caractères Unicode, vous devriez remarquer une différence, car les chaînes JavaScript sont TF-16 ** (détails ci-dessous) et donc certains caractères aura des valeurs supérieures à 255, tandis qu'une "chaîne binaire" selon la spécification de l'API de fichier n'aurait pas de valeurs supérieures à 255 (vous auriez deux "caractères" individuels pour les deux octets du point de code Unicode).
Si vous lisez un fichier qui n'est pas du tout du texte (une image, peut-être), vous obtiendrez probablement un résultat très similaire entre readAsText
et readAsBinaryString
, mais avec readAsBinaryString
vous sachez qu'il n'y aura aucune tentative d'interpréter les séquences multi-octets comme des caractères. Vous ne savez pas que si vous utilisez readAsText
, car readAsText
utilisera un détermination de l'encodage pour essayer de comprendre quel est l'encodage du fichier, puis le mapper sur Les chaînes UTF-16 de JavaScript.
Vous pouvez voir l'effet si vous créez un fichier et le stockez dans autre chose que ASCII ou UTF-8. (Sous Windows, vous pouvez le faire via le Bloc-notes; le "Enregistrer sous" comme encodage). déroulant avec "Unicode" dessus, par lequel en regardant les données, ils semblent signifier UTF-16; je suis sûr que les éditeurs Mac OS et * nix ont une fonctionnalité similaire.) Voici une page qui affiche le résultat de la lecture d'un déposer dans les deux sens:
<!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>
Si j'utilise cela avec un fichier "Testing 1 2 3" stocké en UTF-16, voici les résultats que j'obtiens:
Texte (13): 54 65 73 74 69 6e 67 20 31 20 32 20 33 Binaire (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
Comme vous pouvez le voir, readAsText
a interprété les caractères et j'ai donc obtenu 13 (la longueur de "Testing 1 2 3"), et readAsBinaryString
pas, et j'ai donc obtenu 28 (les deux -byte BOM plus deux octets pour chaque caractère).
* XMLHttpRequest.response avec responseType = "arraybuffer"
est pris en charge dans HTML 5.
** "Les chaînes JavaScript sont en UTF-16" peut sembler étrange; ne sont-ils pas seulement Unicode? Non, une chaîne JavaScript est ne série d'unités de code UTF-16 ; vous voyez les paires de substitution comme deux "caractères" JavaScript individuels même si, en fait, la paire de substitution dans son ensemble n'est qu'un seul caractère. Voir le lien pour plus de détails.