用 C++ 读取文本文件最优雅的方式是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/195323/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:36:43  来源:igfitidea点击:

What is the most elegant way to read a text file with c++?

c++textfile-io

提问by Fang-Pen Lin

I'd like to read whole content of a text file to a std::stringobject with c++.

我想std::string用 C++将文本文件的全部内容读到一个对象中。

With Python, I can write:

使用 Python,我可以写:

text = open("text.txt", "rt").read()

It is very simple and elegant. I hate ugly stuff, so I'd like to know - what is the most elegant way to read a text file with C++? Thanks.

它非常简单和优雅。我讨厌丑陋的东西,所以我想知道 - 用 C++ 读取文本文件的最优雅的方式是什么?谢谢。

回答by Milan Babu?kov

There are many ways, you pick which is the most elegant for you.

有很多方法,你选择最适合你的。

Reading into 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;
}

Into std::string:

进入 std::string:

std::ifstream in("file.txt");
std::string contents((std::istreambuf_iterator<char>(in)), 
    std::istreambuf_iterator<char>());

Into vector<char>:

进入向量<字符>:

std::ifstream in("file.txt");
std::vector<char> contents((std::istreambuf_iterator<char>(in)),
    std::istreambuf_iterator<char>());

Into string, using stringstream:

转成字符串,使用stringstream:

std::ifstream in("file.txt");
std::stringstream buffer;
buffer << in.rdbuf();
std::string contents(buffer.str());

file.txt is just an example, everything works fine for binary files as well, just make sure you use ios::binary in ifstream constructor.

file.txt 只是一个例子,对于二进制文件一切正常,只要确保在 ifstream 构造函数中使用 ios::binary 即可。

回答by Konrad Rudolph

There's another threadon this subject.

关于这个主题还有另一个主题。

My solutions from this thread (both one-liners):

我来自这个线程的解决方案(两个单行):

The nice (see Milan's second solution):

好(见米兰的第二个解决方案):

string str((istreambuf_iterator<char>(ifs)), istreambuf_iterator<char>());

and the fast:

和快速:

string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str());

回答by sharkin

You seem to speak of elegance as a definite property of "little code". This is ofcourse subjective in some extent. Some would say that omitting all error handling isn't very elegant. Some would say that clear and compact code you understand right away is elegant.

你似乎把优雅说成是“小代码”的一个明确属性。这在某种程度上当然是主观的。有人会说省略所有错误处理不是很优雅。有人会说,您立即理解的清晰紧凑的代码是优雅的。

Write your own one-liner function/method which reads the file contents, but make it rigorous and safe underneath the surface and you will have covered both aspects of elegance.

编写您自己的单行函数/方法来读取文件内容,但在表面下使其严格和安全,您将涵盖优雅的两个方面。

All the best

祝一切顺利

/Robert

/罗伯特

回答by Don Pedro

But beware that a c++-string (or more concrete: An STL-string) is as little as a C-String capable of holding a string of arbitraty length - of course not!

但请注意,c++ 字符串(或更具体:STL 字符串)与能够保存任意长度字符串的 C 字符串一样小——当然不是!

Take a look at the member max_size() which gives you the maximum number of characters a string might contain. This is an implementation definied number and may not be portable among different platforms. Visual Studio gives a value of about 4gigs for strings, others might give you only 64k and on 64Bit-platforms it might give you something really huge! It depends and of course normally you will run into a bad_alloc-exception due to memory exhaustion a long time before reaching the 4gig limit...

查看成员 max_size() ,它为您提供字符串可能包含的最大字符数。这是一个实现定义的数字,可能无法在不同平台之间移植。Visual Studio 为字符串提供了大约 4gigs 的值,其他人可能只给你 64k,而在 64Bit 平台上它可能会给你一些非常大的东西!这取决于,当然,通常情况下,在达到 4gig 限制之前,由于内存耗尽很长时间,您会遇到 bad_alloc 异常...

BTW: max_size() is a member of other STL-containers as well! It will give you the maximum number of elements of a certain type (for which you instanciated the container) which this container will (theoretically) be able to hold.

顺便说一句:max_size() 也是其他 STL 容器的成员!它将为您提供该容器(理论上)能够容纳的某种类型(您实例化了容器)的最大元素数量。

So, if you're reading from a file of unknow origin you should:
- Check its size and make sure it's smaller than max_size()
- Catch and process bad_alloc-exceptions

因此,如果您正在读取来源不明的文件,您应该:
- 检查其大小并确保它小于 max_size()
- 捕获并处理 bad_alloc-exceptions

And another point: Why are you keen on reading the file into a string? I would expect to further process it by incrementally parsing it or something, right? So instead of reading it into a string you might as well read it into a stringstream (which basically is just some syntactic sugar for a string) and do the processing. But then you could do the processing directly from the file as well. Because if properly programmed the stringstream could seamlessly be replaced by a filestream, i. e. by the file itself. Or by any other input stream as well, they all share the same members and operators and can thus be seamlessly interchanged!

还有一点:你为什么热衷于将文件读入字符串?我希望通过增量解析它或其他东西来进一步处理它,对吗?因此,与其将其读入字符串,不如将其读入字符串流(基本上只是字符串的一些语法糖)并进行处理。但是你也可以直接从文件中进行处理。因为如果正确编程,字符串流可以无缝地替换为文件流,即文件本身。或者通过任何其他输入流,它们都共享相同的成员和运算符,因此可以无缝互换!

And for the processing itself: There's also a lot you can have automated by the compiler! E. g. let's say you want to tokenize the string. When defining a proper template the following actions:
- Reading from a file (or a string or any other input stream)
- Tokenizing the content
- pushing all found tokens into an STL-container
- sort the tokens alphabetically
- eleminating any double values
can all(!!) be achived in one single(!) line of C++-code (let aside the template itself and the error handling)! It's just a single call of the function std::copy()! Just google for "token iterator" and you'll get an idea of what I mean. So this appears to me to be even more "elegant" than just reading from a file...

对于处理本身:编译器还可以自动执行很多操作!例如 假设您想标记字符串。定义适当的模板时,以下操作:
- 从文件(或字符串或任何其他输入流)读取 - 标记
内容
- 将所有找到的标记推入 STL 容器
- 按字母顺序对标记进行排序
- 删除任何双值
都可以(!!) 在一行 (!) 的 C++ 代码中实现(撇开模板本身和错误处理)!这只是函数 std::copy() 的一次调用!只需在谷歌上搜索“令牌迭代器”,您就会明白我的意思。所以在我看来这比仅仅从文件中读取更“优雅”......

回答by Shadow2531

I like Milan's char* way, but with std::string.

我喜欢米兰的 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";
}

(with or without the ios_base::binary, depending on whether you want newlines tranlated or not. You could also change getfile to just return a string so that you don't have to pass a buffer string in. Then, test to see if the compiler optimizes the copy out when returning.)

(有或没有 ios_base::binary,取决于你是否想要翻译换行符。你也可以将 getfile 更改为只返回一个字符串,这样你就不必传入一个缓冲区字符串。然后,测试看看是否编译器在返回时优化复制。)

However, this might look a little better (and be a lot slower):

但是,这可能看起来好一点(而且速度会慢很多):


#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";
}