Download BLOB content using specified charset
Asked Answered
B

4

44

Is possible to change the Blob charset really? I'm trying it for hours but it doesn't workds. See this.

jQuery("#download").click(function() {
    var csv_content = jQuery("#csv").val(),
        download = document.createElement("a"),
        blob = new Blob([csv_content], { type: "text/csv;charset=ISO-8859-1" });

    download.href = window.URL.createObjectURL(blob);
    download.download = "test.csv";

    var event = document.createEvent("MouseEvents");
    event.initMouseEvent(
        "click", true, false, window, 0, 0, 0, 0, 0
        , false, false, false, false, 0, null
    );
    download.dispatchEvent(event);    
});

I need export a CSV to open on Excel, but it always is save with UTF-8 and Excel can't handle it.

Batsheva answered 20/9, 2013 at 20:20 Comment(0)
B
172

I found the solution before to post.

The change of charset has not been resolved, in fact. However, I sent the UTF-8 header for the download process and Excel was able to understand the file format correctly. Thanks to this response of Erik Töyrä.

blob = new Blob(["\ufeff", csv_content]);
Batsheva answered 20/9, 2013 at 20:20 Comment(4)
Adding "\ufeff" at the beginning really made it work!Shuma
I suspect this works for you because ISO-8859-1 is a subset of UTF-8, so although the browser returns UTF-8, the prefix you added allows Excel to work out what to do. However, in my case the content is Shift-JIS, which is not compatible with UTF-8 so returning the content re-encoded in UTF-8 is not an option.Kroeger
That did the trick also for me! In my case, what is represented here by the "csv_content" variable, was an array of strings. So I just did it like so: ["\ufeff", ...str_arr]. Obviously, the spread operation in JS didn't even exist at the time this question was submitted (and answered), but today it does and it's very useful.Incunabulum
For letter ñ made it work!Caldeira
K
11

In my case I was using Angular JS to receive an encoded CSV file from the server in response to an HTTP POST. The problem was that CSVs returned from XMLHttpRequests are represented as Unicode (I want to say UTF-8, but according to this it is UTF-16) strings, not pre-encoded binary data. It looks like this is true in your example too, it is reading the CSV from a DOM element? In this case it ends up being represented as Unicode in memory, so it doesn't matter what value you set the encoding metadata to, the data is still Unicode.

My Angular code was doing something like this:

$http.post('/url', postData, {}).then(handleResponse);

Inside handleResponse, the data was already represented in Unicode. According to Angular's $http service, not providing the responseType property on the config object causes it to default to string. Which according to Mozilla ends up represented as a DOMString in UTF-16, whereas we actually want it to be a Blob. Setting the responseType to blob on the config object successfully prevented the content from getting decoded. Without this, the response data was being inadvertently decoded before being placed into the Blob.

$http.post('/url', postData, {responseType: 'blob'}).then(handleResponse);

I then used saveAs() to get the browser to provide the file contents to the user.

function handleResponse(response) {
    let headers = response.headers();
    let blob = new Blob([response.data], {type: headers['content-type']});
    saveAs(blob, headers['x-filename']);
}

I got the idea to set responseType from https://mcmap.net/q/374816/-how-to-read-binary-data-in-angularjs-in-an-arraybuffer

Kroeger answered 26/4, 2016 at 11:44 Comment(3)
Thanks! This was my exact problem, minus the angular.Lesalesak
Glad to help, and glad that replying to a three year old accepted answer question helped out someone else so quickly.Kroeger
saved hours of debugging for me. Thank you!Deciliter
O
3
  const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' });
    if (navigator.msSaveBlob) { // IE 10+
      navigator.msSaveBlob(blob, filename);
    } else {
      const link = document.createElement('a');
      if (link.download !== undefined) {
        // Browsers that support HTML5 download attribute
        const url = URL.createObjectURL(blob);
        link.setAttribute('href', url);
        link.setAttribute('download', filename);
        link.style.visibility = 'hidden';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
      }
    }

this worked for csv export with excel format in vuejs.

Ouphe answered 21/5, 2020 at 7:8 Comment(0)
C
0

If you have some symbols in the csv and the accepted solution is not solving the problem:

blob = new Blob(["\ufeff", csv_content]);
// for csv_content you can try like below.
function b64DecodeUnicode(str: any) {        
        return decodeURIComponent(atob(str).split('').map((c: any) => {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
        }).join(''));
    }
Craze answered 8/8, 2018 at 9:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.