C++1z ファイルシステムライブラリ

C++1zでは、ファイルパス、ディレクトリ、ファイルのコピー・移動などを扱うファイルシステムライブラリが導入されます。

このライブラリは、Boost Filesystem Library v3をベースにしています。basic_path<CharT>のように文字型をパラメータとするのではなく、pathクラスが用意され、内部で文字エンコーディングが行われます。

C++1zのファイルシステムライブラリが議論されていくにつれてBoost.Filesystemも追従して更新されていますので、Boost 1.61.0現在では、この2つの差異は小さくなっています。

ファイルシステムライブラリの機能は、<filesystem>ヘッダのstd::filesystem名前空間で定義されます。

#include <filesystem>

namespace fs = std::filesystem;

int main()
{
    fs::path p1 = "C:/";
    fs::path p2 = "a.txt";

    // operator/()で2つのパスを連結する
    // operator+=(), concat()メンバ関数を使用してもよい
    fs::path p = p1 / p2;

    // ファイルをfromからtoにコピーする
    // エラーが発生した場合は、std::filesystem::filesystem_error例外が送出される
    fs::path from = p;
    fs::path to = "C:/b.txt";
    fs::copy_file(from, to);
}

エラー報告

ファイルシステムライブラリのエラー報告は、std::filesystem::filesystem_error例外を送出するか、std::error_codeオブジェクトを返すかのどちらかを、ユーザーが選択できます。

ファイルコピーの場合は、以下のようになります:

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main()
{
    fs::path from = "C:/a.txt";
    fs::path to = "C:/b.txt";

    // デフォルトでは、エラー発生時に例外を送出する
    try {
        fs::copy_file(from, to);
    }
    catch (fs::filesystem_error& e) {
        std::cout << e.what() << std::endl;
        throw;
    }

    // 最後の引数にerror_codeオブジェクトへの参照を渡すと、
    // 例外送出の代わりにerror_codeオブジェクトにエラー情報が格納される
    std::error_code error;
    fs::copy_file(from, to, error);
    if (error) {
        std::cout << error.message() << std::endl;
    }
}

文字エンコーディング

std::filesystem::pathクラスは、文字コード関係の機能が内部に入っており、OSネイティブの文字コードでファイルパス文字列を取得したり、自分がほしい文字コードでファイルパス文字列を取得できたりします。

native()メンバ関数は、OSネイティブの文字コードでファイルパス文字列のstd::basic_stringを返します。文字の型は、POSIXベースのOSではcharWindowsではwchar_tになります。文字コードもOSネイティブのものになります。

// Windowsの場合
path p = "a.txt";
path::string_type str = p.native(); // string_typeはstd::wstring型
// POSIXベースOSの場合
path p = "a.txt";
path::string_type str = p.native(); // string_typeはstd::string型

文字コードを指定したい場合は、以下のメンバ関数を使用します。

メンバ関数 文字コード
std::string string() const OSネイティブのマルチバイ文字コード
std::wstring wstring() const OSネイティブのワイド文字コード
std::string u8string() const UTF-8
std::u16string u16string() const UTF-16
std::u32string u32string() const UTF-32

Unicodeの正規化に関する規定はとくにありません。

パスの汎用フォーマット

パスのフォーマットには、たとえばWindows"C:\\a.txt"ようにバックスラッシュでディレクトリを区切るものと、"C:/a.txt"のようにスラッシュで区切るものがあり、後者をこのライブラリでは汎用パスフォーマット(generic path format)と呼んでいます。

汎用フォーマットでパス文字列を取得したい場合に、以下のメンバ関数が使用できます。

template <class EcharT, class traits = char_traits<EcharT>,
          class Allocator = allocator<EcharT> >
basic_string<EcharT, traits, Allocator>
  generic_string(const Allocator& a = Allocator()) const;

std::string generic_string() const;
std::wstring generic_wstring() const;
std::string generic_u8string() const;
std::u16string generic_u16string() const;
std::u32string generic_u32string() const;

文字コードは、前述したものと同様です。

Boost.Filesystemとの差異

Boost 1.61.0のBoost.Filesystemライブラリと比較して、設計として以下の差異があります。

日時を表す型が、Boost.Filesystemライブラリではstd::time_tですが、標準の方はstd::chrono::time_point<trivially-clock>となっています。Clockの型は実装定義です。日時は、ファイルの最終日時を取得・設定する際に使用します。

ロケールの扱いが少し違います。Boost.Filesystemのpathクラスはimbue()メンバ関数を持っていますが、標準の方はありません。Boost.Filesystemのpathクラスはコンストラクタでcodecvtオブジェクトをとりますが、標準の方はlocaleオブジェクトをとります。 私が少し調べて気づいたのはこれくらいです。細かい機能のありなしはありますが、設計として異なるのはこれくらいでしょう。

参照

お断り

この記事の内容は、C++1zが正式リリースされる際には変更される可能性があります。正式リリース後には、C++日本語リファレンスサイトcpprefjpの以下の階層の下に解説ページを用意する予定です。