テキストファイルの読み込み・書き込み【C#/WinRT】

Windowsにおけるテキスト入出力は.NETのAPIのほかに、WindowsのプラットフォームAPIであるWinRT APIを用いて実装することも可能です。Unicodeしか扱えないという制約はありますが、StorageFileインスタンスから直接テキスト入出力を行うことができます。ここでは、WinRT APIを用いたテキストファイルの読み込みと書き込みの方法を説明します。

開発環境

  • .NET 6.0
  • WinUI 3.0 (Windows App SDK 1.0)
  • WinRT Build 22000

C#におけるテキストファイルの読み込み・書き込み

C#でテキストファイルを扱うには.NETクラスライブラリを使う方法(StreamReader / StreamWriter など)に加えて、WindowsではWinRTのテキスト入出力APIを用いることもできます。StorageFileインスタンスから直接テキストの入出力を行うことができるので、他のWinRT APIも使っている場合はテキスト入出力もWinRT APIに合わせることで可読性の高いコードを書くことができます。ただし、Unicodeしか扱えないという制約もあるので、目的に応じて使い分ける必要があります。

ここではWinRT APIを用いてテキストファイルの読み込み・書き込みを行う方法を説明していきます。

FileIO / PathIOを使ったテキスト入出力

WinRT APIではファイルの読み込み・書き込みのためのヘルパー・メソッドをまとめたFileIOクラスとPathIOクラスが用意されています。FileIOクラスにはStorageFileとして取得したテキストファイルを操作するためのメソッドがまとめられています。PathIOクラスにもFileIOクラスと同様のメソッドが用意されていますが、FileIOクラスのメソッドは引数にStorageFileオブジェクトを指定するのに対して、PathIOクラスのメソッドは引数にファイルパスを文字列として指定します。

サンプル・プログラム

ここでは、FileIOクラスのメソッドを使ってテキストの読み込みや書き込みを行うプログラムをWinUI3アプリとして作成してみます。

MainWindow

MainWindow.xaml
<Window ...(省略)... >

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="35"/>
        </Grid.RowDefinitions>
        <TextBox x:Name="txtBox" VerticalAlignment="Stretch" TextWrapping="Wrap" AcceptsReturn="True" Grid.Row="0"/>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Grid.Row="1">
            <Button Click="OpenButton_Click">開く</Button>
            <Button Click="SaveButton_Click">保存</Button>
        </StackPanel>
    </Grid>
</Window>
MainWindow.xaml.cs
public sealed partial class MainWindow : Window
{

    public MainWindow()
    {
        this.InitializeComponent();
    }

    // [開く]ボタンの処理
    private async void OpenButton_Click(object sender, RoutedEventArgs e)
    {
        // ファイル選択ダイアログの表示
        var picker = new FileOpenPicker();
        picker.FileTypeFilter.Add(".txt");
        InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(this));
        StorageFile storageFile = await picker.PickSingleFileAsync();

        // テキストファイルを開く
        if (storageFile != null) txtBox.Text = await FileIO.ReadTextAsync(storageFile);
    }

    // [保存]ボタンの処理
    private async void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        // ファイル保存ダイアログの表示
        var picker = new FileSavePicker();
        picker.FileTypeChoices.Add("テキストファイル", new List<string>() { ".txt" });
        InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(this));
        StorageFile storageFile = await picker.PickSaveFileAsync();

        // テキストファイルを保存する
        if (storageFile != null) await FileIO.WriteTextAsync(storageFile, txtBox.Text);
    }
}

これで以下のように[開く]ボタンでテキストファイルの内容を表示したり、[保存]ボタンでTextBoxに入力した内容を保存したりできるようになりました。

ファイルからテキストを読み込む

[開く]ボタンを押したときの処理は10-20行目にコーディングされています。13-16行目はファイル選択ダイアログを表示させるためのコードとなり、詳細は以下をご覧ください。

ファイル選択ダイアログにより開きたいファイルをStorageFileインスタンスとして取得し、19行目でFileIOクラスのReadTextAsyncメソッドの引数に指定することでテキストファイルのテキストを取得しています。

このように、ファイルからテキストを読み込むときはFileIOクラスのReadTextAsyncメソッドもしくはReadLinesAsyncメソッドを用います。ReadTextAsyncメソッドはファイル内容をすべて1つのテキストファイルとして取得するのに対して、ReadLinesAsyncメソッドでは行ごとにテキストを読み込んで、リスト形式で取得します。なお、このReadTextAsyncメソッドはUTF-8やUTIF-16などのUnicodeの文字列の読み込みにしか対応していないので、シフトJISなどのほかのエンコードの文字列を読み込むと文字化けしたりエラーになったりしてしまうことに注意が必要です。

ファイルへのテキストの書き込み

[保存]ボタンを押したときの処理は23-33行目にコーディングされています。26-29行目でファイル保存ダイアログを表示させ、保存するファイルをStorageFileインスタンスとして取得しています。続いて、32行目でWriteTextAsyncメソッドの引数にそのStorageFileインスタンスと保存する文字列を指定することで、その文字列を保存することができます。

この時、テキストを行ごとに保存する場合はWriteLinesAsyncメソッドを用います。また、エンコードはデフォルトでUTF-8となります。

テキストファイルの最後にテキストを追加

すでに存在するテキストファイルの末尾に文字列を追加する場合は、AppendTextAsyncメソッドやAppendLinesAsyncメソッドを用いることが簡単に実装できます。

例えばファイルをstorageFile(StorageFileインスタンス)として取得して、その末尾に「Hello, world」と追加する場合は、

await FileIO.AppendTextAsync(storageFile, "Hello, world");

とします。

PathIOを用いる方法

FileIOクラスのメソッドでは一度ファイルをStorageFileインスタンスとして取得する必要がありましたが、PathIOクラスのメソッドを使えばファイルの絶対パスをそのまま指定することでテキスト入出力が行えます。例えば、「C:\BioTech-Lab\sample.txt」を読み込む場合は次のようにします。

string text = await PathIO.ReadTextAsync(@"C:\BioTech-Lab\sample.txt");

PathIOクラスにはFileIOと同じメソッドがそのまま用意されているので、StorageFileで指定するかファイルパスで指定するか使いやすい方を選ぶことができます。

WinRT APIの他のテキスト入出力

ここまで説明してきたFileIO / PathIOを使う方法はテキスト入出力をシンプルに実装することができて非常に強力な方法ですが、テキストサイズがメモリに載り切らないほど巨大な場合などは使えません。また、複数の処理をひとまとめにしたメソッドなので、エラーが起きた場合に何が原因かが分かりにくくなるなどのデメリットもあります。そのため、WinRT APIではバッファーを用いる方法やストリームを用いる方法も用意されています。その使い分けについては以下をご覧ください。

シフトJISでエンコードされたテキストを読み込む方法

WinRTでは標準ではUnicodeしかサポートされていないので、シフトJISを扱うためには.NETのクラスライブラリを参照する必要があります。そのため、先ほどのFileIOPathIOクラスを用いる方法では、デフォルトでUnicode (UTF-8)となっていて、シフトJISなどは使えません。そこで、ここではシフトJISでエンコードされたテキストを読み込む方法を見ていきましょう。シフトJISを使えるようにするための実装方法にはいくつかありますが、ここではWinRTストリームを.NETストリームに変換して、シフトJISのテキストを読み込む方法を説明します。

先ほどのサンプル・プログラムの[開く]ボタンを押されたときの処理を次のように変更してみます。

// [開く]ボタンの処理
private async void OpenButton_Click(object sender, RoutedEventArgs e)
{
    // ファイル選択ダイアログの表示
    var picker = new FileOpenPicker();
    picker.FileTypeFilter.Add(".txt");
    InitializeWithWindow.Initialize(picker, WindowNative.GetWindowHandle(this));
    StorageFile storageFile = await picker.PickSingleFileAsync();

    // テキストファイルを開く
    if (storageFile != null)
    {
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        using (Stream stream = (await storageFile.OpenReadAsync()).AsStream())
        using (StreamReader reader = new StreamReader(stream, Encoding.GetEncoding("shift_jis")))
        {
            txtBox.Text = await reader.ReadToEndAsync();
        }
    }
}

.NET6ではデフォルトでシフトJISを選べないので、まず21行目を追加しておく必要があります。その上で、22行目でまずStorageFileのOpenReadAsyncメソッドでWinRTストリームを取得し、AsStreamメソッドで.NETストリームに変換しています。あとは、.NETストリームにおけるテキスト入出力となるので、23-26行目でStreamReaderを用いてテキストを取得しています。

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)