Atomでファイルを読み書きするパッケージを作る際にUTF-8以外の文字コードにも対応する方法メモ

More than 3 years have passed since last update.


結論

ファイルの読み書きをする際にFileクラスを使いsetEncodingで適切な文字コードを指定しましょう、以上。


蛇足

TextEditorであればCore Packagesのencoding-selectorでよしなに設定できるので問題ないが、例えばTablrのように独自の編集画面を作りファイルの読み書きをする場合は自身で文字コードを適切に処理する必要がある。

(なお、例に挙げたTablrは文字コードの処理を行っていないためUTF-8なCSVしか扱えない)

2016/01/18 Update

Tablr 0.10.0より文字コードの処理が入り、UTF-8以外の文字コードであっても扱えるようになった。

node-pathwatcher/file.coffee at master · atom/node-pathwatcherreadSyncwriteFileSyncの実装を見ると以下のようになっている。

  readSync: (flushCache) ->

if not @existsSync()
@cachedContents = null
else if not @cachedContents? or flushCache
encoding = @getEncoding()
if encoding is 'utf8'
@cachedContents = fs.readFileSync(@getPath(), encoding)
else
iconv ?= require 'iconv-lite'
@cachedContents = iconv.decode(fs.readFileSync(@getPath()), encoding)

@setDigest(@cachedContents)
@cachedContents

writeFileSync: (filePath, contents) ->
encoding = @getEncoding()
if encoding is 'utf8'
fs.writeFileSync(filePath, contents, {encoding})
else
iconv ?= require 'iconv-lite'
fs.writeFileSync(filePath, iconv.encode(contents, encoding))

ここのgetEncodingで取得している文字コードはsetEncodingでセットした文字コードであるため、実際にファイルを読み書きする前に文字コードのセットが必要となる。

文字コードの変換にはiconv-liteを使っていることから、iconv-liteで対応できる文字コードであればFileクラスを使い適切な値をsetEncodingで指定してやれば読み書きの際に変換のことを考える必要はなくなる。


文字コードの自動判定をしたい場合

残念ながらFileクラスには文字コードの自動判別処理が入っていない。

encoding-selectorには文字コードの自動判別処理が実装されているが、外部からこれを利用する方法はないため自前で実装しなければならないようだ。

  detectEncoding: ->

filePath = @editor.getPath()
return unless fs.existsSync(filePath)

jschardet = require 'jschardet'
iconv = require 'iconv-lite'
fs.readFile filePath, (error, buffer) =>
return if error?

{encoding} = jschardet.detect(buffer) ? {}
encoding = 'utf8' if encoding is 'ascii'
return unless iconv.encodingExists(encoding)

encoding = encoding.toLowerCase().replace(/[^0-9a-z]|:\d{4}$/g, '')
@editor.setEncoding(encoding)