Local Folder

Local Folder の入出力です。

前田稔の超初心者のプログラム入門

ファイルを作成

  1. Local Folder には、アプリケーションに関連するファイルを格納することが出来ます。
    他のメトロのアプリが保存されているファイルにはアクセスすることが出来ず、アプリ毎に独立しています。
    アプリをインストールすると Local Folder が作成され、アンインストールすると完全に消去されます。
    今回は簡単な TEXT DATA を格納したファイル(test.txt)を Local Folder に書き出してみましょう。
  2. Visual Studio 2019 を立ち上げて [Blank App(Universal Windows - C++/CX)]を選択して下さい。
    「ボタン1」をクリックすると "test.txt" に現在時刻を書き込み「ボタン2」をクリックすると入力して TextBox に表示します。
    MainPage.xaml を直接編集して二個のボタンと TextBox を貼り付けます。
        <Grid>
            <Button x:Name="button" Content="Write" Margin="40,40,0,0" VerticalAlignment="Top" Click="Button1_Click"/>
            <Button x:Name="button1" Content="Read" Margin="160,40,0,0" VerticalAlignment="Top" Click="Button2_Click"/>
            <TextBox x:Name="textBox" HorizontalAlignment="Left" Margin="70,100,0,0" Text="TextBox"
                VerticalAlignment="Top" Width="200"/>
        </Grid>
    
  3. MainPage.xaml.h でボタンクリックの関数を定義して下さい。
        private:
            void Button1_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
            void Button2_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    
  4. MainPage.xaml.cpp でボタンクリックを検出して "test.txt" の Write と Read を行います。
    create_task() を使うので ppltasks.h を #include して、namespace で concurrency; と Windows::Storage; を定義して下さい。
    #include <ppltasks.h>
    using namespace concurrency;
    using namespace Windows::Storage;
    
  5. Write ボタンのクリックで、現在の時刻を格納した "test.txt" を作成します。
    ①String^ result に現在時刻を設定します。
    result は create_task() に渡すので static で宣言して下さい。
    ②StorageFolder に LocalFolder を設定します。
    ③CreateFileAsync() で StorageFile を作成します。
    ④WriteTextAsync() でファイルに現在時刻を書き込みます。
    void App1::MainPage::Button1_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        Windows::Globalization::Calendar^ cal = ref new Windows::Globalization::Calendar();
        auto longTime = ref new Windows::Globalization::DateTimeFormatting::DateTimeFormatter("longtime");
        DateTime time = cal->GetDateTime();
        static String^ result = longTime->Format(time);
        StorageFolder^ folder =
            Windows::Storage::ApplicationData::Current->LocalFolder;
        create_task(folder->CreateFileAsync(L"test.txt", CreationCollisionOption::ReplaceExisting)).then(
            [this](StorageFile^ file) 
        {
            return FileIO::WriteTextAsync(file, result);
        }).then([this](task<void> previousTask) 
        {
            try
            {   previousTask.get();  }
            catch (Platform::Exception^)
            {  }
        });
    }
    
  6. Read ボタンのクリックで "test.txt" からテキストを入力して TextBox に表示します。
    ①StorageFolder に LocalFolder を設定します。
    ②GetFileAsync() で StorageFile を取得します。
    ③ReadTextAsync(file) でファイルからデータを入力します。
    ④previousTask.get() で String^ str に格納して、TextBox に表示します。
    void App1::MainPage::Button2_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        StorageFolder^ folder =
            Windows::Storage::ApplicationData::Current->LocalFolder;
        create_task(folder->GetFileAsync(L"test.txt")).then([this](StorageFile^ file) 
        {
            return FileIO::ReadTextAsync(file);
        }).then([this](task<void> previousTask) 
        {
            try
            {   String^ str = previousTask.get();
                textBox->Text = "test.txt: " + str;
            }
            catch (...)
            {   textBox->Text = "test.txt: <not found>";  }
        });
    }
    
  7. コンパイル&実行して「Write」ボタンをクリックすると "test.txt" に現在時刻を書き込みます。
    「Read」ボタンをクリックすると "test.txt" からデータを取得して TextBox に表示します。
  8. Local Folder の場所は「C:\Users\<ユーザ名>\AppData\Local\Packages\<アプリID>\LocalState\」になります。
    今回は「C:\Users\maeda\AppData\Local\Packages\28d59b92-fd46-41c0-b87a-2d44d05db34d_m3b2cat7fbs4m\」でした。
    この中の \LocalState\ を調べると "test.txt" が格納されていました。
    同様のプログラムを StoreCS の Text Local でも作成しています。

【NOTE】

★不可解な現象が起こっています。
2019/05/04 Visual Studio Professional 2019 16.0.3 にバージョンアップして試しても結果は変わりません。
2019/06/06 Visual Studio Professional 2019 16.1.2 にバージョンアップして試しても結果は変わりません。
2019/06/12 Visual Studio Professional 2019 16.1.3 にバージョンアップして試しても結果は変わりません。

Visual Studio Professional 2019 で作成すると MainPage.xaml.cpp の [this] から赤の下線が消えません。
このエラーは task を使った他のプロジェクトでも起こっています。
Windows8 & Visual Studio Express 2012 のときは、エラーは無かったと思うのですが? (^_^;)
ビルドすると正常にコンパイル出来たようなので、実行してみると動きました。

所が一度目の [Write] ボタンをクリックすると、正常に "test.txt" に現在時刻が書き込まれたのですが、 二度,三度と [Write] ボタンをクリックしても時刻が変わりません。
私はクリックされた時刻を "test.txt" に書き込んでいるつもりで、クリックする毎に時刻が変わるはずなのですが、どこを間違えているのでしょうか? (^_^;)

その後の調査で判明したことは static String^ result で定義した領域の値が [Write] ボタンをクリックした時刻に更新されていないようです。
Button1_Click() で wstr と result の値を確認します。
void App1::MainPage::Button1_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    Windows::Globalization::Calendar^ cal = ref new Windows::Globalization::Calendar();
    auto longTime = ref new Windows::Globalization::DateTimeFormatting::DateTimeFormatter("longtime");
    DateTime time = cal->GetDateTime();
    String^ wstr = longTime->Format(time);
    static String^ result = longTime->Format(time);

    OutputDebugString(wstr->Data());
    OutputDebugString(result->Data());
OutputDebugString で印字した結果を見ると、wstr にはクリックされた時刻が格納されていますが、result の値は変わっていません。
‎11‎:‎17‎:‎12   11‎:‎17‎:‎12    // 最初のクリック
‎11‎:‎17‎:‎20   11‎:‎17‎:‎12    // 2度目のクリック
‎11‎:‎17‎:‎27   11‎:‎17‎:‎12    // 3度目のクリック
static で定義されていない wstr を WriteTextAsync() で使うとエラーになります。
FileIO::WriteTextAsync(file, wstr);

プロジェクトが完成

  1. 試行錯誤の結果 [Write] ボタンをクリックした時刻を "test.txt" に書き込むことが出来るようになりました。
    二度,三度と [Write] ボタンをクリックするとクリックした時刻がファイルに書き込まれます。
    MainPage.xaml.h のソースコードです。
    LocalPut() 関数でファイルに書き込みます。
    wstr が書き込む TEXT を格納する領域です。
        public ref class MainPage sealed
        {
        public:
            MainPage();
        private:
            void Button1_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
            void Button2_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
            void LocalPut(Platform::String^ str);
            Platform::String^ wstr;
        };
    
  2. Button1_Click() 関数では、クリックされた時刻を result に格納して LocalPut() 関数を呼び出します。
    void App1::MainPage::Button1_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
        Windows::Globalization::Calendar^ cal = ref new Windows::Globalization::Calendar();
        auto longTime = ref new Windows::Globalization::DateTimeFormatting::DateTimeFormatter("longtime");
        DateTime time = cal->GetDateTime();
        Platform::String^ result = longTime->Format(time);
        LocalPut(result);
    }
    
  3. LocalPut() 関数では、パラメータで渡された str を "test.txt" ファイルに書き出します。
    void App1::MainPage::LocalPut(Platform::String^ str)
    {
        wstr = str;
        StorageFolder^ folder =
            Windows::Storage::ApplicationData::Current->LocalFolder;
        create_task(folder->CreateFileAsync(L"test.txt", CreationCollisionOption::ReplaceExisting)).then(
            [this](StorageFile^ file) 
        {
            return FileIO::WriteTextAsync(file, wstr);
        }).then([this](task<void> previousTask)
        {
            try
            {   previousTask.get();  }
            catch (Platform::Exception^)
            {  }
        });
    }
    
  4. プログラムの完成は、まるでパズルを解くようなもので「あれこれいじくりまわして」やっと思うように動作するようになりました。
    パズルなら必ず答えがあるはずですが、こちらは答えがあるとは限らないのですからより難しいかも知れません。
    [this] の赤い下線はそのままで、ソースコードを見るたびに非常に気になります。

超初心者のプログラム入門(C/C++)