2

I have some string need to be a UTF-16 text file. For example:

var s = "aosjdfkzlzkdoaslckjznx";
var file = "data:text/plain;base64," + btoa(s);

This will result a UTF-8 encoding text file. How can I get a UTF-16 text file with string s?

4
  • Does your file need to be in a data: URL? 'cause you can easily do what you want with a Blob. Commented Oct 4, 2015 at 18:50
  • Yes, I need base64. But I don't like fileReaderAPI because it's asynchronous. It will make my app too complex. Do you have better suggestion? Commented Oct 4, 2015 at 19:20
  • I suggest you reevaluate your criteria. Web apps use async stuff, it's inevitable. But as it happens, using TextEncoder and creating a Blob URI won't be async. You don't need the File API because you're not reading a file, you're creating one. Commented Oct 4, 2015 at 20:49
  • I use the arrayBuffer directly convert to base64 with this: stackoverflow.com/questions/9267899/… Commented Oct 4, 2015 at 21:01

2 Answers 2

13

Related: Javascript to csv export encoding issue

This should do it:

document.getElementById('download').addEventListener('click', function(){

	downloadUtf16('Hello, World', 'myFile.csv')
});

function downloadUtf16(str, filename) {

	// ref: https://stackoverflow.com/q/6226189
	var charCode, byteArray = [];

	// BE BOM
  byteArray.push(254, 255);

	// LE BOM
  // byteArray.push(255, 254);

  for (var i = 0; i < str.length; ++i) {
  
    charCode = str.charCodeAt(i);
    
    // BE Bytes
    byteArray.push((charCode & 0xFF00) >>> 8);
    byteArray.push(charCode & 0xFF);
    
    // LE Bytes
    // byteArray.push(charCode & 0xff);
    // byteArray.push(charCode / 256 >>> 0);
  }
  
  var blob = new Blob([new Uint8Array(byteArray)], {type:'text/plain;charset=UTF-16BE;'});
  var blobUrl = URL.createObjectURL(blob);
  
	// ref: https://stackoverflow.com/a/18197511
  var link = document.createElement('a');
  link.href = blobUrl;
  link.download = filename;

  if (document.createEvent) {
    var event = document.createEvent('MouseEvents');
    event.initEvent('click', true, true);
    link.dispatchEvent(event);
  } else {
    link.click();
  }
}
<button id="download">Download</button>

Sign up to request clarification or add additional context in comments.

3 Comments

Does the trick for me! but, in your example you are working with BE BOM, but encode your blob with charset UTF-16LE. Shouldn't that be UTF-16BE then?
You save my life.
Does this also work for Unicode surrogate pairs (see the charCodeAt and codePointAt documentation), i.e. characters/emojis with a unicode value greater than 0xFFFF?
1

You can use a legacy polyfill of the native TextEncoder API to transform a JavaScript string into an ArrayBuffer. As you'll see in that documentation, UTF16 with either endianness is was supported. Libraries that provide UTF-16 support in a Text-Encoder-compatible way will probably appear soon, if they haven't already. Let's assume that one such library exposes a constructor called ExtendedTextEncoder.

Then you can easily create a Blob URL to allow users to download the file, without the inefficient base-64 conversion.

Something like this:

s = "aosjdfkzlzkdoaslckjznx"
var encoder = new ExtendedTextEncoder("utf-16be")
var blob = new Blob(encoder.encode(s), "text/plain")
var url = URL.createObjectURL(blob)

Now you can use url instead of your data: URL.

6 Comments

Just note, UTF-16LE text file has a magic header(FF,FE or 255,254). See: en.wikipedia.org/wiki/…
I'm sorry but I found this doesn't works in Safari. Safari just doesn't support TextEncoder() . Is there any other solution for Safari?
You can use a polyfill for TextEncoder. I can recommend the one I linked, I've used it myself. It will create a TextEncoder object that behaves just like the native one (only if it's not avaialble natvely).
Oh this is my first time heard about polyfill. Thanks and it works!
TextEncoder does not accept an encoding string as a parameter any more: developer.mozilla.org/en-US/docs/Web/API/TextEncoder/…
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.