JavaScript -> 下载使用 ISO-8859-1 / Latin1 / Windows-1252 编码的 CSV 文件

6
我已经编写了一个小工具来提取亚马逊CSV订单数据中的运输数据,它已经可以使用。以下是一个简单版本的JS Bin链接:http://output.jsbin.com/jarako
为了打印邮票/运输标签,我需要一个文件上传到德国邮政和其他包裹服务商。我使用了一个在stackoverflow上找到的小函数saveTextAsFile。目前一切都很好。输出文本区域或下载的文件中没有显示出错的特殊字符(äöüß...)。
所有这些德国邮政/包裹服务网站只接受latin1 / iso-8859-1编码的文件进行上传。但是我的下载文件总是utf-8格式。如果我上传它,所有的特殊字符(äöüß...)都会出错。
我该如何更改它呢?我已经尝试了很多方法,例如:将工具的字符集设置为iso-8859-1。
<META http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />

但结果是:现在输出文本区域和下载的文件中仍然有错误的特殊字符。如果我上传到帖子网站,我仍然会得到更多的错误字符。即使我在CODA编辑器中检查编码,它仍然显示下载的文件是UTF-8。 saveTextAsFile 函数使用 var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'});。也许有一种方法可以在下载时设置字符集!?
function saveTextAsFile()
{
    var textToWrite = $('#dataOutput').val();
    var textFileAsBlob = new Blob([textToWrite], {type:'text/plain'});
    var fileNameToSaveAs = "Brief.txt";

    var downloadLink = document.createElement("a");
    downloadLink.download = fileNameToSaveAs;
    downloadLink.innerHTML = "Download File";
    if (window.webkitURL != null)
    {
        // Chrome allows the link to be clicked
        // without actually adding it to the DOM.
        downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
    }
    else
    {
        // Firefox requires the link to be added to the DOM
        // before it can be clicked.
        downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
        downloadLink.onclick = destroyClickedElement;
        downloadLink.style.display = "none";
        document.body.appendChild(downloadLink);
    }

    downloadLink.click();
}

无论如何,必须有一种方法可以下载其他编码的文件,因为该网站使用的编码与Amazon网站不同。我从Amazon网站下载CSV文件时,它是UTF-8编码的。但是,如果我在CODA中检查下载的CSV文件,则其为Latin1(iso-8859-1)编码...

3个回答

8
请向下滚动,查看真正的解决方案更新!
因为我没有得到答案,所以我不断地进行了更多搜索。在Javascript中似乎没有解决方案。每次测试下载我都使用的是Javascript生成的UTF-8编码。看起来Javascript只适用于UNICODE / UTF-8编码,或者其他编码(可能)只适用于数据再次使用以前的HTTP传输。但对于客户端运行的Javascript来说,不会发生任何额外的HTTP传输,因为数据仍在客户端。
现在我已经通过在我的服务器上构建一个小型PHP脚本来帮助自己,我可以通过GET或POST请求将数据发送到该脚本。它将编码转换为latin1 / ISO-8859-1,并将其作为文件下载。这是一个带有正确编码特殊字符的ISO-8859-1文件,我可以将其上传到提到的邮政和包裹服务网站上,一切看起来都很好。 latin-download.php: (非常重要的是,将PHP文件本身也保存为ISO-8859-1,这样才能使其正常工作!)
<?php
$decoded_a = urldecode($_REQUEST["a"]);
$converted_to_latin = mb_convert_encoding($decoded_a,'ISO-8859-1', 'UTF-8');
$filename = $_REQUEST["filename"];
header('Content-Disposition: attachment; filename="'.$filename.'"; content-type: text/plain; charset=iso-8859-1;');
echo $converted_to_latin;
?>

在我的 JavaScript 代码中,我使用:
<a id="downloadlink">Download File</a>

<script>
var mydata = "this is testdata containing äöüß";

document.getElementById("downloadlink").addEventListener("click", function() {
    var mydataToSend = encodeURIComponent(mydata);
    window.open("latin-download.php?a=" + mydataToSend + "&filename=letter-max.csv");
}, false);
</script>

对于更大量的数据,您需要从GET切换到POST...

更新 2016年2月8日

现在我已经在纯JavaScript中找到了解决方案。使用inexorabletash/text-encoding。这是编码标准的一个polyfill。该标准包括解码旧编码(如latin1(“windows-1252”)),但它禁止编码为这些旧编码类型。因此,如果您使用浏览器实现的window.TextEncoder函数,则只提供UTF编码。但是,polyfill solution提供了一种旧模式,它允许编码成旧编码,如latin1。

我像这样使用它:

<!DOCTYPE html>
<script>
// 'Copy' browser build in TextEncoder function to TextEncoderOrg (because it can NOT encode windows-1252, but so you can still use it as TextEncoderOrg()  )
var TextEncoderOrg = window.TextEncoder;   
// ... and deactivate it, to make sure only the polyfill encoder script that follows will be used 
window.TextEncoder = null;  

</script>
<script src="lib/encoding-indexes.js"></script>  // needed to support encode to old encoding types
<script src="lib/encoding.js"></script>  // encording polyfill

<script>

function download (content, filename, contentType) {
    if(!contentType) contentType = 'application/octet-stream';
        var a = document.createElement('a');
        var blob = new Blob([content], {'type':contentType});
        a.href = window.URL.createObjectURL(blob);
        a.download = filename;
        a.click();
}

var text = "Es wird ein schöner Tag!";

// Do the encoding
var encoded = new TextEncoder("windows-1252",{ NONSTANDARD_allowLegacyEncoding: true }).encode(text);

// Download 2 files to see the difference
download(encoded,"windows-1252-encoded-text.txt");
download(text,"utf-8-original-text.txt");

</script>

encoding-indexes.js文件大小约为500kb,因为它包含了所有编码表。由于我只需要windows-1252编码,在我的使用中,我已经删除了此文件中的其他编码。现在只剩下632字节。


6
问题不在于编码,而是某些应用程序(例如Microsoft Excel)中特殊字符显示错误。UTF-8可以正常显示所有特殊的德语字符。您可以通过在csv文件前添加字节顺序标记(BOM)来解决此问题。
const BOM = "\uFEFF" 
let csvData = BOM + csvData
const blob = new Blob([csvData], { type: "text/csv;charset=utf-8" });

基于这篇Github帖子的解决方案。

这可能是针对接受UTF-8的服务的解决方案,但不适用于希望使用latin1 / iso-8859-1编码的CSV数据的服务。无论如何,感谢您的帖子。但是存在一个问题,如果要在前面添加BOM,则必须使用以下代码: let csvData = BOM + csvData - Lutz

2

你无法强制要求 Web 服务器以特定编码发送数据,只能礼貌地请求。将数据转换为所需格式的方法是正确的方式。

如果您想避免使用 PHP 脚本,可以尝试在创建 Blob 时指定编码作为参数:

var textFileAsBlob = new Blob(textToWrite, {
  type: 'text/plain;charset=ISO-8859-1', 
  encoding: "ISO-8859-1"
});

请查看在Google Chrome中指定Blob编码以获取更多详细信息。


1
感谢您的反馈,Jacob。我仍然尝试了'new Blob(textToWrite, { encoding:"UTF-8", type:"text/plain;charset=UTF-8"});'和类似的东西,但在我的Chrome中,我从blob下载的所有文件都是UTF-8编码的文件,当我检查它们时。-所以现在看起来我不得不接受通过服务器的方式… - Lutz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接