3
votes

Le téléchargement de Blob avec le type 'text / csv' élimine la nomenclature Unicode

J'essaie d'enregistrer un fichier CSV à l'aide de JavaScript, avec une nomenclature UTF-8 ajoutée au début. Cependant, lors de la vérification du fichier téléchargé, il semble que la nomenclature est toujours supprimée. Le code suivant reproduit le problème:

var csv = '\ufeff\ufefftest,test2';

L'ajout du caractère BOM à la chaîne deux fois produit le résultat correct:

var csv = '\ufefftest,test2';
var blob = new Blob([csv], {type: 'text/csv;charset=utf-8'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'test.csv';
document.body.appendChild(a);
a.click();

Le fichier résultant doit avoir le caractère BOM au début. p >

Pourquoi est-il supprimé dans cet exemple?

EDIT: Mon cas d'utilisation génère un fichier CSV et s'assure que le fichier peut être ouvert avec un encodage correct par Microsoft Excel. Je pense que la nomenclature est peut-être détectée et tronquée, mais Excel a besoin que le caractère soit présent pour détecter UTF-8.


2 commentaires

Cela se produit-il dans plusieurs navigateurs? Que se passe-t-il si vous ne spécifiez pas de jeu de caractères?


@OllyHodgson Cela se produit dans Firefox et Chrome


3 Réponses :


3
votes

Ma meilleure hypothèse est que certains navigateurs peuvent interpréter la nomenclature dans le texte et la tronquer.

J'ai ajouté un exemple où la nomenclature est ajoutée par un ArrayBuffer au Blob . Cela semble fonctionner.

Mais sachez que la nomenclature que vous essayez d'ajouter est la nomenclature UTF-16 (BE) pas la nomenclature UTF-8 EF BB BF . https://de.wikipedia.org/wiki/Byte_Order_Mark

var csv = 'test,test2';

// create BOM UTF-8
var buffer = new ArrayBuffer(3);
var dataView = new DataView(buffer);
dataView.setUint8(0, 0xfe);
dataView.setUint8(1, 0xbb);
dataView.setUint8(2, 0xbf);
var read = new Uint8Array(buffer);

// create BOM UTF-16
var buffer = new ArrayBuffer(2);
var dataView = new DataView(buffer);
dataView.setUint8(0, 0xfe);
dataView.setUint8(1, 0xff);
var read = new Uint8Array(buffer);

var blob = new Blob([read /*prepend bom*/, csv], {type: 'text/csv;charset=utf-8'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'test.csv';
document.body.appendChild(a);
a.click();


2 commentaires

Lors de l'ouverture du fichier résultant dans Emacs, il ne semble pas détecter l'encodage UTF-8, affichant simplement 3 caractères de jeu de caractères latins pour ces points de code.


Comme je l'ai dit dans la réponse, le BOM FEFF n'est PAS le BOM UTF-8 mais le UTF-16 (BE).



0
votes

Votre nomenclature est ici.

C'est simplement que tout ce que vous utilisez pour le lire le supprime, puisque, eh bien, il ne devrait pas faire partie du texte.
Cependant, si vous effectuez un vidage HEX ou le lisez comme un ArrayBuffer, vous verrez qu'il est toujours là:

<br><label>you can reupload it here too<input type="file" id="inp"></label>
const csv = '\ufefftest,test2';
const blob = new Blob([csv], {type: 'text/csv;charset=utf-8'});
download(blob);
read(blob);

inp.onchange = e => read(inp.files[0]);

async function read(blob) {
  // grab the byte content
  const buf = await new Response(blob).arrayBuffer();
  // stupidly map to some string characters
  const str = [...new Uint8Array(buf)]
    .map(c => String.fromCharCode(c)); // only for the demo, this doesnt convert from bytes to string in UTF-8!
  console.log(str);
}

function download(blob) {
  const a = document.createElement('a');
  a.download = 'file.csv';
  a.href = URL.createObjectURL(blob);
  a.textContent = 'download';
  document.body.prepend(a);
}

Et notez que l'autre réponse est juste en ce que votre nomenclature est en fait celle de UTF-16BE, mais ce n'est pas encore votre problème.


0 commentaires

0
votes
var csv = 'test,test2';

var blob = new Blob([decodeURIComponent('%ef%bb%bf') /*prepend bom*/, csv], {type: 'text/csv;charset=utf-8'});
var url = URL.createObjectURL(blob);
var a = document.createElement('a');
a.href = url;
a.download = 'test.csv';
document.body.appendChild(a);
a.click();

0 commentaires