通过函数打开流
Opening stream via function
本文关键字:函数 更新时间:2023-10-16
我需要关于[io](f)stream
s的不可复制性的帮助。
我需要提供一个关于fstream
s的破解包装,以便在Windows上处理文件名中包含unicode字符的文件。为此,我设计了一个包装器函数:
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
线是罪魁祸首。我也尝试过从函数返回流,但它导致了同样的问题。std::istream
的复制构造函数是delete
d。我也尝试过std::move
,但没有帮助。我该如何解决这个问题?
编辑:多亏了@tibur的想法,我终于找到了一个很好的方法来实现Keep It Simple (TM)
,而且功能强大。从某种意义上说,它仍然很黑客,因为它依赖于使用的Windows标准C++库,但由于只有两个真正的库在使用,这对我来说并不是一个真正的问题。
#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
析构函数确实负责关闭文件,因此任何地方都不需要额外的内存管理。
关于:
ifstream * open_ifstream(const string &filename);
您不能直接使用rdbuf
成员函数来设置stream
的缓冲区吗?
这里有一个不太直观的想法:
#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());
我建议一个小的改进:使用_wopen
(或_wsopen_s
)而不是_wfopen
。您将获得一个文件描述符(int
),可以将其传递给stdio_filebuf
来代替FILE*
。通过这种方式,您应该避免泄漏任何资源(正如marcin所指出的)
相关文章:
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- 函数调用中参数的顺序重要吗
- 函数向量_指针有不同的原型,我可以构建一个吗
- 使用不带参数的函数访问结构元素
- 代码在main()中运行,但在函数中出现错误
- 内置函数可查看CPP中的成员变量
- 如何获取std::result_of函数的返回类型
- 如何在c++中为模板函数实例创建快捷方式
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗