Upload
chibochibo
View
973
Download
1
Embed Size (px)
Citation preview
nioで作ったBufferedWriterに変えたら例外になった
2016-2-13第十四回 #渋谷java
自己紹介
島本 多可子(@chibochibo03)
株式会社ビズリーチ CTO室
普段はScalaを書いてます
GitBucketやってます
https://github.com/gitbucket/gitbucket
直近の著書です →
ある日
変更前
普通に生成していた
val charset: String = …
new BufferedWriter( new OutputStreamWriter( new FileOutputStream(new File("...")), charset ))
変更後
深く考えずnioのFiles.newBufferedWriterに変更
val charset: String = …
Files.newBufferedWriter( Paths.get("..."), Charset.forName(charset))
例外発生
Σ( ̄Д ̄;)なぬぅっ!!
java.nio.charset.UnmappableCharacterException
スタックトレース
Failed to import XML. java.nio.charset.UnmappableCharacterException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:282) at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:285) at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125) at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207) at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129) at java.io.BufferedWriter.close(BufferedWriter.java:265)
(´へ`;ウーム
(━_━)ゝウーム
ハッ (゚Д゚;)!!
どうやら化ける文字に対する扱いが異なるようだ
こんなテストコードを用意
// 通常版
def normal() = { val charset = "EUC_JP" val data = "Java"+ "\u3030" +"Scala"
IO(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("...")), charset))).using { writer => IO { writer.write(data) writer.flush() } }}
こんなテストコードを用意
// 通常版
def normal() = { val charset = "EUC_JP" val data = "Java"+ "\u3030" +"Scala"
IO(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(new File("...")), charset))).using { writer => IO { writer.write(data) writer.flush() } }}
Javaで、EUC_JPで出力不可な文字
結果
// 変換できない文字は'?'に置換
Java?Scala
nioの場合
// nio版def nio() = { val charset = "EUC_JP" val data = "Java"+ "\u3030" +"Scala"
IO(Files.newBufferedWriter(Paths.get("..."), Charset.forName(charset))).using { writer => IO { writer.write(data) writer.flush() } }}
結果
// 例外が発生し、出力もおかしなことに
JavaJava
(;¬д¬) アヤシイ
スタックトレース
Failed to import XML. java.nio.charset.UnmappableCharacterException: Input length = 1 at java.nio.charset.CoderResult.throwException(CoderResult.java:282) at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:285) at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125) at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207) at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129) at java.io.BufferedWriter.close(BufferedWriter.java:265)
StreamEncoder.implWrite
CharsetEncoder.encodeの結果次第
CharsetEncoderはどうやって決まる?
newBufferedWriterの場合
newBufferedWriterの場合
newBufferedWriterでたどり着く先
エンコードエラー時の動作は指定なし => CodingErrorAction.REPORT
CodingErrorAction.REPORTエラーが発生した時点で処理を中断し、エラーを報告する
従来の場合
従来でたどり着く先
不正入力エラー、マッピング不可エラー時の動作指定あり
CodingErrorAction.REPLACEエラーが発生した入力文字を指定した文字に置換して出力し、処理を継続する
デフォルトは「?」
設定されている置換文字列はreplacement メソッドで取得可能
(o゚∀゚)o キタ――♪
これが答え
CharsetEncoder.encode - 一部抜粋
newBufferedWriterの場合
従来の場合
まとめ
エンコードエラー時、置換文字による代替で処理を継続するか、エラーを通知してほしい
か、時と場合による
特に外部からのデータフィードの場合は、変な文字が紛れ込む
すぐに対応してもらえないことも・・・
nioのFiles.newBufferedWriterはエンコードエラー時に例外を投げるので注意