什么是最优雅的方式来阅读一个文本文件与C + +?
我想阅读一个文本文件的全部内容到一个std::string
对象与c + +。
用Python,我可以这样写:
text = open("text.txt", "rt").read()
这是非常简单和优雅。 我讨厌丑陋的东西,所以我想知道 – 用C ++读取文本文件最优雅的方式是什么? 谢谢。
有很多方法,你select哪一个最适合你。
读入char *:
ifstream file ("file.txt", ios::in|ios::binary|ios::ate); if (file.is_open()) { file.seekg(0, ios::end); size = file.tellg(); char *contents = new char [size]; file.seekg (0, ios::beg); file.read (contents, size); file.close(); //... do something with it delete [] contents; }
进入std :: string:
std::ifstream in("file.txt"); std::string contents((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
进入vector <char>:
std::ifstream in("file.txt"); std::vector<char> contents((std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
进入string,使用stringstream:
std::ifstream in("file.txt"); std::stringstream buffer; buffer << in.rdbuf(); std::string contents(buffer.str());
file.txt只是一个例子,一切工作正常的二进制文件,只要确保您在ifstream构造函数中使用ios :: binary。
这个主题还有另外一个线索 。
我从这个线程(这两个单行)的解决scheme:
很好(见米兰的第二个解决scheme):
string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());
和快速:
string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str());
你似乎把优雅说成是“小代码”的一个固定属性。 这在一定程度上是主观的。 有人会说,省略所有的error handling不是很优雅。 有人会说,你明白的清晰而紧凑的代码是优雅的。
编写自己的单行函数/方法来读取文件内容,但在表面之下进行严格和安全的处理,将涵盖优雅的两个方面。
祝一切顺利
/罗伯特·
但是要小心,一个c ++string(或者更具体的:一个STLstring)就像一个Cstring一样可以保存一串长度的string – 当然不是!
看看成员max_size(),它给你一个string可能包含的最大字符数。 这是一个实现定义的数字,可能不能在不同的平台之间移植。 Visual Studio为string提供了大约4gig的值,其他的可能只给你64k,在64位平台上可能会给你一些非常大的值! 这取决于,通常你会遇到一个bad_alloc例外,由于内存耗尽很长时间才达到4gig限制…
顺便说一下:max_size()也是其他STL容器的成员! 它会给你这个容器(理论上)能容纳的某种types的元素的最大数量(为此你实例化容器)。
所以,如果你从一个不知名的来源文件阅读,你应该:
– 检查它的大小,确保它小于max_size()
– 捕获并处理bad_alloc-exceptions
还有一点:为什么你热衷于将文件读入string? 我希望通过逐步parsing它或进一步处理它,对吧? 所以不要将它读入string,而应该将它读入一个stringstream(基本上只是一些string的语法糖)并进行处理。 但是,你也可以直接从文件中进行处理。 因为如果编程正确,stringstream可以被文件stream无缝replace,也就是文件本身。 或者通过其他任何inputstream,他们都共享相同的成员和运营商,因此可以无缝地互换!
对于处理本身而言:编译器还可以自动执行很多操作! 例如, 假设你想标记string。 在定义适当的模板时,请执行以下操作:
– 从文件(或string或任何其他inputstream)读取
– 标记内容
– 将所有find的标记推入STL容器
– 按字母顺序对令牌进行sorting
– 消除双重价值
所有(!!)都可以在一行(!)的C ++代码行中实现(不用模板本身和error handling)! 这只是一个函数std :: copy()的调用! 只是谷歌的“令牌迭代器”,你会明白我的意思。 所以这在我看来比从文件中读取更“优雅”…
我喜欢米兰的char *方式,但是用std :: string。
#include <iostream> #include <string> #include <fstream> #include <cstdlib> using namespace std; string& getfile(const string& filename, string& buffer) { ifstream in(filename.c_str(), ios_base::binary | ios_base::ate); in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit); buffer.resize(in.tellg()); in.seekg(0, ios_base::beg); in.read(&buffer[0], buffer.size()); return buffer; } int main(int argc, char* argv[]) { if (argc != 2) { cerr << "Usage: this_executable file_to_read\n"; return EXIT_FAILURE; } string buffer; cout << getfile(argv[1], buffer).size() << "\n"; }
(有或没有ios_base :: binary,取决于你是否想要换行或者不换行,也可以改变getfile来返回一个string,这样你就不必传入一个缓冲区string了。编译器在返回时优化拷贝。)
但是,这可能看起来好一点(而且会慢很多):
#include <iostream> #include <string> #include <fstream> #include <cstdlib> using namespace std; string getfile(const string& filename) { ifstream in(filename.c_str(), ios_base::binary); in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit); return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>()); } int main(int argc, char* argv[]) { if (argc != 2) { cerr << "Usage: this_executable file_to_read\n"; return EXIT_FAILURE; } cout << getfile(argv[1]).size() << "\n"; }