3

s のコピー不可能な性質について助けが必要[io](f)streamです。

fstreamWindows でファイル名に Unicode 文字を含むファイルを処理するには、s の周りにハック的なラッパーを提供する必要があります。このために、ラッパー関数を考案しました。

bool open_ifstream( istream &stream, const string &filename )
{
#ifdef __GLIBCXX__
    FILE* result = _wfopen( convert_to_utf16(filename).c_str(), L"r" );
    if( result == 0 )
        return false;

    __gnu_cxx::stdio_filebuf<char>* buffer = new __gnu_cxx::stdio_filebuf<char>( result, std::ios_base::in, 1 );
    istream stream2(buffer);
    std::swap(stream, stream2);

#elif defined(_MSC_VER)
    stream.open( convert_to_utf16(filename) );
#endif
    return !!stream;
}

もちろん、std::swapラインが犯人です。関数からストリームを返すことも試みましたが、同じ問題が発生します。a のコピー コンストラクタstd::istreamdeleted です。私も試してみましたstd::moveが、それは役に立ちませんでした。この問題を回避するにはどうすればよいですか?

編集:Keep It Simple (TM) @tiburのアイデアのおかげで、私はついに良い方法を見つけましたが、機能的です。使用されている Windows 標準 C++ ライブラリに依存するという意味ではまだハックですが、実際に使用されているのは 2 つだけなので、私にとってはそれほど問題ではありません。

#include <fstream>
#include <memory>
#if _WIN32
# if __GLIBCXX__
#  include<ext/stdio_filebuf.h>
unique_ptr<istream> open_ifstream( const string &filename )
{
    FILE* c_file = _wfopen( convert_to_utf16(filename).c_str(), L"r" );
    __gnu_cxx::stdio_filebuf<char>* buffer = new __gnu_cxx::stdio_filebuf<char>( c_file, std::ios_base::in, 1 );

    return std::unique_ptr<istream>( new istream(buffer) );
}
# elif _MSC_VER
unique_ptr<ifstream> open_ifstream( const string &filename )
{
    return unique_ptr<ifstream>(new ifstream( convert_to_utf16(filename)) );
}
# else
# error unknown fstream implementation
# endif
#else
unique_ptr<ifstream> open_ifstream( const string &filename )
{
    return unique_ptr<ifstream>(new ifstream(filename) );
}
#endif

そしてユーザーコードでは:

auto stream_ptr( open_ifstream(filename) );
auto &stream = *stream_ptr;
if( !stream )
    return emit_error( "Unable to open nectar file: " + filename );

これは C++0x<memory>autoキーワードに依存します。もちろんclose、結果のstream変数だけを取得することはできませんが、GNU Libstdc++std::istreamデストラクタがファイルを閉じる処理を行うため、余分なメモリ管理はどこにも必要ありません。

4

4 に答える 4

3

どうですか:

ifstream * open_ifstream(const string &filename);
于 2011-06-29T17:41:50.443 に答える
3

rdbufメンバー関数を使用してstreamのバッファを直接設定できませんでしたか?

于 2011-06-29T17:40:03.000 に答える
2

適度に邪魔にならないアイデアを次に示します。

#include <iconv.h>
#include <algorithm>

void windowify(std::string & filename)
{
#ifdef WIN32
  assert(filename.length() < 1000);

  wchar_t wbuf[1000];
  char    cbuf[1000];
  char * ip = &cbuf[0];
  char * op = reinterpret_cast<char*>(&wbuf[0]);

  size_t ib = filename.length(), ob = 1000;

  std::fill(cbuf + filename.length(), cbuf + 1000, 0);
  std::copy(filename.begin(), filename.end(), cbuf);

  iconv_t cd = iconv_open("WCHAR_T", "UTF-8");
  iconv(cd, &ip, &ib, &op, &ob);
  iconv_close(cd);

  wchar_t sfnbuf[1000];
  std::fill(cbuf, cbuf + 1000, 0);

  ib = GetShortPathNameW(wbuf, sfnbuf, 1000);
  ob = 1000;
  ip = reinterpret_cast<char*>(&wbuf[0]);
  op = &cbuf[0];

  cd = iconv_open("UTF-8", "WCHAR_T");
  iconv(cd, &ip, &ib, &op, &ob);
  iconv_close(cd);

  filename = std::string(cbuf);
#endif
}

使用法:

std::string filename = getFilename();
windowify(filename);
std::ifstream infile(filename.c_str());
于 2011-06-29T18:25:27.883 に答える
1

小さな改善をお勧めします:の代わりに_wopen(または) を使用します。の代わりに に渡すことができるファイル記述子 ( ) を取得します。このようにして、リソースのリークを避ける必要があります(marcinが指摘したように)_wsopen_s_wfopenintstdio_filebufFILE*

于 2015-04-14T08:31:18.957 に答える