我想用c ++将文本文件的全部内容读取到std::string
对象。
使用Python,我可以写:
text = open("text.txt", "rt").read()
非常简单而优雅。我讨厌丑陋的东西,所以我想知道 - 用C ++读取文本文件最优雅的方法是什么? 感谢。
答案 0 :(得分:123)
有很多方法,你选择哪种方式最适合你。
阅读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&lt; char&gt;:
std::ifstream in("file.txt");
std::vector<char> contents((std::istreambuf_iterator<char>(in)),
std::istreambuf_iterator<char>());
使用stringstream:
进入字符串std::ifstream in("file.txt");
std::stringstream buffer;
buffer << in.rdbuf();
std::string contents(buffer.str());
file.txt只是一个例子,一切都适用于二进制文件,只需确保在ifstream构造函数中使用ios :: binary。
答案 1 :(得分:11)
关于这个主题有another thread。
我的解决方案来自这个主题(两个单行):
很好(见米兰的第二个解决方案):
string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());
和快速:
string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str());
答案 2 :(得分:4)
你似乎把优雅说成是“小代码”的明确属性。这在某种程度上是主观的。有人会说省略所有错误处理并不是很优雅。有人会说,你立即理解的清晰紧凑的代码是优雅的。
编写您自己的单行函数/方法,读取文件内容,但在表面下使其严谨安全,您将涵盖优雅的两个方面。
一切顺利
/罗伯特
答案 3 :(得分:1)
但请注意,c ++ - 字符串(或更具体的:一个STL字符串)与能够容纳一串任意长度的C字符串一样少 - 当然不是!
查看成员max_size(),它给出了字符串可能包含的最大字符数。这是一个实现定义的数字,可能无法在不同平台之间移植。 Visual Studio为字符串提供了大约4gig的值,其他的可能只给你64k,在64Bit平台上它可能会给你一些非常大的东西!这取决于当然通常你会在达到4gig限制之前的很长一段时间内由于内存耗尽而遇到bad_alloc异常......
BTW:max_size()也是其他STL容器的成员!它将为您提供此容器(理论上)能够容纳的特定类型(您为其设备容器)的最大元素数。
因此,如果您正在阅读未知来源的文件,您应该:
- 检查其大小并确保它小于max_size()
- 捕获并处理bad_alloc-exceptions
另一点: 你为什么热衷于将文件读成字符串?我期望通过逐步解析它或其他东西来进一步处理它,对吗?因此,不是将其读入字符串,而是将其读入字符串流(基本上只是字符串的一些语法糖)并进行处理。但是你也可以直接从文件中进行处理。因为如果正确编程,字符串流可以无缝地被文件流替换,i。即由文件本身。或者通过任何其他输入流,它们都共享相同的成员和操作符,因此可以无缝地互换!
对于处理本身:编译器还可以自动化很多东西! E. g。假设您想要对字符串进行标记。定义适当的模板时,请执行以下操作:
- 从文件(或字符串或任何其他输入流)读取
- 对内容进行标记
- 将所有找到的令牌推入STL容器中
- 按字母顺序对标记进行排序
- 消除任何双重值
所有(!!)都可以在单个(!)的C ++行代码中实现 - 代码(放弃模板本身和错误处理)!它只是函数std :: copy()的一次调用!只需谷歌“令牌迭代器”,你就会明白我的意思。因此,在我看来,这比仅仅从文件中读取更加“优雅”......
答案 4 :(得分:0)
我喜欢米兰的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只返回一个字符串,这样你就不必传入一个缓冲区字符串。然后,测试查看编译器在返回时是否优化副本。)
然而,这看起来可能会好一些(并且速度要慢得多):
#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";
}