シフトJISのEncodingオブジェクトを取得するには?[Windows 10 UWPアプリ開発]:WinRT/Metro TIPS
UWPでは既定でサポートされているエンコーディングがASCIIとUnicodeだけとなっている。そのため、シフトJIS形式のテキストファイルを扱うためにひと手間が必要になる。
powered by Insider.NET
日本向けにWindows 10のユニバーサルWindowsプラットフォーム用のアプリ(以降、UWPアプリ)を作るとき、いまだにシフトJISを扱わねばならない場面は多い。シフトJISで書かれたファイルは多く残っているだろう。WebサイトにもシフトJISを使っているところはいまだに多い(EUCやJISを使っているところもある)。しかし、これまでのWindowsストアアプリのつもりでEncodingオブジェクト(System.Text名前空間)を取得しようとすると、.NET Coreを使うようになったUWPではうまくいかない(ASP.NET 5でも同様)。
そこで本稿では、UWPアプリでEncodingオブジェクトを取得する方法を解説する。なお、本稿のサンプルは「Windows Store app samples:MetroTips #114」からダウンロードできる。
事前準備
デスクトップ用とモバイル(=Windows 10を搭載したスマートフォン)用のUWPアプリを開発するには、以下の開発環境が必要である。本稿では、無償のVisual Studio Community 2015(およびVisual Studio Tools for Universal Windows Appsバージョン1.1)を使っている。
- SLAT対応のPC*1
- 64bit版*2 Windows 10 Pro*3
- Visual Studio 2015(以降、VS 2015)*4
- Windows SDK for Windows 10*5、およびVisual Studio Tools for Universal Windows Apps*6
*1 SLAT対応ハードウエアは、モバイルエミュレーターの実行に必要だ。ただし未対応でも、ソースコードのビルドと実機でのデバッグは可能である。SLAT対応のチェック方法はMSDNブログの「Windows Phone SDK 8.0 ダウンロードポイント と Second Level Address Translation (SLAT) 対応PCかどうかを判定する方法」を参照。なお、SLAT対応ハードウエアであっても、VM上ではエミュレーターが動作しないことがあるのでご注意願いたい。
*2 Windows 10モバイルエミュレーターを使用しないのであれば、32bit版でもよい。
*3 開発に使うWindows 10は「開発者モード」を有効にしておくこと(「設定アプリ」の[更新とセキュリティ]−[開発者向け]で、[開発者モード]ラジオボタンを選択)。そうしないと、VS 2015のXAMLエディターがエラーになる。また、本稿の内容が適用できるのは、Windowsのライフサイクル管理の上では「Windows 10, released in July 2015」と呼ばれるリリース、またはそれ以降。WinVerコマンドで表示されるバージョンは「10.0 (ビルド 10240)」。UWPアプリ開発におけるデバイスファミリーのバージョン指定としては「10.0.0.0」(Package.appxmanifestファイルのTargetDeviceFamily)である。なお、モバイルエミュレーターを使用しないのであれば、Home版でもよい。
*4 本稿に掲載したコードを試すだけなら、無償のExpressエディションやCommunityエディションで構わない。Visual Studio Express 2015 for Windows 10(製品版)はマイクロソフトのページから無償で入手できる(ページの左側で[Visual Studio 2015]−[Express 2015 for Windows 10]と選ぶ)。Expressエディションはターゲットプラットフォームごとに製品が分かれていて紛らわしいが、UWPアプリの開発には「for Windows 10」を使う(「for Desktop」はWPF/Windowsフォーム/Win32 APIのアプリ開発用)。また、Visual Studio Community 2015(製品版)もマイクロソフトのページから無償で入手できる。なお、英語版がインストールされた場合には、Microsoft Visual Studio 2015 Language Packの日本語版を追加インストールし、[オプション]ダイアログで言語を切り替える。
*5 使用しているVS 2015に含まれていない場合は、Windows SDK for Windows 10のページからダウンロードできる。本稿の内容が適用できるのは、作成したプロジェクトのプロパティに表示されるターゲットバージョンが「10.0; ビルド 10240」またはそれ以降。
*6 Visual Studio Tools for Universal Windows Appsは、2015年9月16日付でバージョン1.1に上がっている。それ以前に開発環境を整えた人は、個別にアップデートする必要がある。「Update 1.1: Release Notes and Installation Instructions」(英語)を参照。
シフトJISのEncodingを取得するときの問題
まず、これまでのような書き方をすると、どのような問題が発生するのかを確認しておこう。
ここではシフトJISのテキストファイルを読み込むコードを考えよう。実行ファイルと同じフォルダーに「Sample.txt」という名前でシフトJISのテキストファイルを用意しておき、それを読み込んでその内容を「textBox1」という名前のTextBoxコントロール(Windows.UI.Xaml.Controls名前空間)に表示するコードは、これまでのストアアプリ(Windowsランタイムアプリ)であれば次のようになるだろう。
textBox1.Text = "【単にEncoding.GetEncoding(\"Shift_JIS\")を呼び出し】\n\n";
// テキストファイルを開いてバイナリのまま読み込む
var file = await Windows.ApplicationModel.Package.Current
.InstalledLocation.TryGetItemAsync("Sample.txt")
as Windows.Storage.StorageFile;
if (file == null)
return;
var buff = await Windows.Storage.FileIO.ReadBufferAsync(file);
// Encodingオブジェクトを取得し、バイナリを文字列に変換する
try
{
var enc = System.Text.Encoding.GetEncoding("Shift_JIS");
textBox1.Text += enc.GetString(buff.ToArray());
}
catch (Exception ex)
{
textBox1.Text += ex.ToString();
}
textBox1.Text = "【単にEncoding.GetEncoding(""Shift_JIS"")を呼び出し】" + vbCrLf + vbCrLf
' テキストファイルを開いてバイナリのまま読み込む
Dim file = TryCast(
Await Windows.ApplicationModel.Package.Current _
.InstalledLocation.TryGetItemAsync("Sample.txt"),
Windows.Storage.StorageFile)
If (file Is Nothing) Then
Return
End If
Dim buff = Await Windows.Storage.FileIO.ReadBufferAsync(file)
' Encodingオブジェクトを取得し、バイナリを文字列に変換する
Try
Dim enc = System.Text.Encoding.GetEncoding("Shift_JIS")
textBox1.Text += enc.GetString(buff.ToArray())
Catch ex As Exception
textBox1.Text += ex.ToString()
End Try
これまでであれば、このコードのように単に「Encoding.GetEncoding("Shift_JIS")」を呼び出すだけでシフトJISのEncodingオブジェクトを取得できた。
なお、GetEncodingメソッドの引数については「.NET TIPS:Encodingクラスで扱えるエンコーディング名は?[C#、VB]」を参照。
ところが上のコードをビルドして動かしてみると、シフトJISのEncodingオブジェクトを取得するところで例外が発生するのである(次の画像)。
シフトJISのEncodingオブジェクトを取得するところで例外が発生(デスクトップ)
上はデバッグビルド、下はリリースビルド(=Nativeコンパイル)である。別途公開のサンプルプログラムの実行結果から、ファイルの内容を表示するため使用しているTextBoxコントロールの部分のみ掲載した(例外発生時にはその内容を表示するようになっている)。
エラーメッセージから、GetEncodingメソッドの呼び出しで例外が発生していると分かる。デバッグビルドの方のメッセージにある「see the documentation for the Encoding.RegisterProvider method」が、解決のヒントになる。
なお、Windows 10 Mobileでも同様の結果になる。
UWPでは(正確には.NET Coreでは)、ASCIIとUnicode以外のエンコーディングが既定ではサポートされなくなったため、このようなエラーになってしまうのである*7。
*7 MSDNの「CodePagesEncodingProvider Class」の解説に「.NET Core(中略)supports only the following encodings:」とあって、サポートされているエンコーディングの一覧が載っている。
シフトJISのEncodingを取得するには?
既定ではASCIIとUnicode以外のエンコーディングがサポートされていないといっても、Windowsのシステムが提供しているエンコーディングを利用する方法は用意されている。何だか面倒な仕組みに変わったわけだが、おそらくは実行時のフットプリントを削減するための措置であろう。
シフトJISのEncodingを取得するには、「Encoding.GetEncoding("Shift_JIS")」を呼び出す前に、次の1行を追加すればよい*8。
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance)
このコードは、EncodingクラスのGetEncodingメソッドを呼び出す前のどこに置いてもよい。
これで、Windowsのシステムが提供しているエンコーディングの全てを利用できるようになる。
このコードを適当な場所に追加して(それこそAppクラスのコンストラクターでも構わない)、実行してみてほしい。今度はシフトJISのEncodingオブジェクトが取得できるはずだ(次の画像)。
シフトJISのテキストファイルを表示している例
左側はデスクトップでの実行、右側はWindows 10 Mobileエミュレーターでの実行である(どちらもリリースビルド)。
また、Windows 10 Mobileの実機でも動作した(インサイダープレビュー版ビルド10512)。
なお、このコードは、UWPアプリで必ずシフトJISエンコーディングが使えることを保証するものではない。Windowsのシステムが提供しているエンコーディングにシフトJISが含まれていなければ、実行時エラーになるだろう。Windows 10は、さまざまなデバイスで動作する。デバイスによってはシフトJISをサポートしていないものがあるかもしれないのだ。
*8 本稿で示した以外に、NuGetから入手できるPortable.Text.Encodingを使う方法もある。DLLを追加する分だけ配布するパッケージサイズは大きくなってしまうが、Windows Phone 8.xやXamarinなどでも利用可能だ。ソースコードを見ると自前で文字コード変換テーブルを持っている実装のようなので、WindowsのシステムがシフトJISのエンコーディングを提供しているかどうかを気にしなくて済むだろう。
ちなみに、Portable.Text.Encodingの最初のリリースは2014年3月であり、それ以前はWindows Phone 8.xでシフトJISを扱うためにはWin32 APIを使うコードを書くことが多かった。「WinRT/Metro TIPS:シフトJISのデータを読み取るには?[WP 8]」参照。
まとめ
UWPアプリでは(正確には.NET Coreでは)、「Encoding.GetEncoding("Shift_JIS")」を呼び出す前に「おまじない」が必要である。
Copyright© Digital Advantage Corp. All Rights Reserved.