如何读取文件并将其写入字符串C++

发布于 2025-02-04 18:39:41 字数 404 浏览 2 评论 0 原文

我找到了一个解决方案,但我相信有更好的方法可以做到这一点。如何在不使用复杂工具的情况下改进代码?

string Read(string& file) {
    ifstream in;
    string text;
    string s;
    in.open(file, ios::in);
    try {
        while (!in.eof()) {
            text.append(s);
            in >> s;
        }
    }
    catch (exception& ex) {
        cout << ex.what();
    }
    in.close();
    return text; 
}

I found a solution but I believe there are better ways to do it. How can I improve my code without using complicated tools?

string Read(string& file) {
    ifstream in;
    string text;
    string s;
    in.open(file, ios::in);
    try {
        while (!in.eof()) {
            text.append(s);
            in >> s;
        }
    }
    catch (exception& ex) {
        cout << ex.what();
    }
    in.close();
    return text; 
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夜光 2025-02-11 18:39:41

您的代码读取了空格分离的单词,丢弃了空格,并将所有单词连接成一个没有空格的字符串。您可能想逐字阅读文件内容。


将整个文件读取到 std :: String 无循环的一种方法是使用 std :: String constructor> constructor,该构建器带有两个迭代器 - 构造函数为您执行循环。用 std :: istreambuf_iterator

#include <string>
#include <fstream>
#include <iterator>
#include <stdexcept>

std::string read(std::string filename) {
    std::ifstream file(filename, std::ios_base::binary | std::ios_base::in);
    if(!file.is_open())
        throw std::runtime_error("Failed to open " + filename);
    using Iterator = std::istreambuf_iterator<char>;
    std::string content(Iterator{file}, Iterator{});
    if(!file)
        throw std::runtime_error("Failed to read " + filename);
    return content;
}

另一种选择是将文件映射到内存(零copy方法),例如使用 boost :: iostreams :: iostreams :: mapped_file_file 它曾经得到。该方法对于大于〜100KB的文件的速度更快,基准获得了硬数字。

一个优化是立即填充文件映射的所有页面,而不是需求分页首先访问。

例子:

#include <iostream>
#include <boost/iostreams/device/mapped_file.hpp>

int main() {
    using boost::iostreams::mapped_file;
    mapped_file content("/etc/lsb-release", mapped_file::readonly);
    std::cout.write(content.const_data(), content.size());
}

Your code reads whitespace-separated words, discards the whitespace, and concatenates all words into one string with no whitespace. You probably want to read the file content verbatim.


One way to read an entire file into a std::string without a loop is to use std::string constructor which takes two iterators - the constructor does the loop for you. Invoke it with std::istreambuf_iterator:

#include <string>
#include <fstream>
#include <iterator>
#include <stdexcept>

std::string read(std::string filename) {
    std::ifstream file(filename, std::ios_base::binary | std::ios_base::in);
    if(!file.is_open())
        throw std::runtime_error("Failed to open " + filename);
    using Iterator = std::istreambuf_iterator<char>;
    std::string content(Iterator{file}, Iterator{});
    if(!file)
        throw std::runtime_error("Failed to read " + filename);
    return content;
}

Another alternative is to map the file into memory (zero-copy method), e.g. using boost::iostreams::mapped_file, that's as clean and efficient as it ever gets. The method is faster for files larger than ~100kB, benchmark to get hard numbers.

An optimization would be to populate all the pages of the file mapping immediately, rather than with demand paging on first access.

Example:

#include <iostream>
#include <boost/iostreams/device/mapped_file.hpp>

int main() {
    using boost::iostreams::mapped_file;
    mapped_file content("/etc/lsb-release", mapped_file::readonly);
    std::cout.write(content.const_data(), content.size());
}
安稳善良 2025-02-11 18:39:41

最简单的方法(通常意味着最好的方法)是一次读取文件一个字符

string text;
char ch;
while (file.get(ch)) {
    text += ch;
}

The simplest way (which often times means the best way) is to read the file one character at a time

string text;
char ch;
while (file.get(ch)) {
    text += ch;
}
呆° 2025-02-11 18:39:41

循环

while (!in.eof()) {
    text.append(s);
    in >> s;
}

是错误的,因为条件 while(!in.eof())即使以前的语句 in&gt;&gt; S 成功。最好写,而(!in.fail())而不是 while(!in.eof())

但是,像这样编写循环会更清晰,效率更高:

while ( in >> s ) {
    text.append(s);
}

这种循环条件间接使用 in.operator bool() ,这等同于!in.fail()

该循环比另一个循环更有效的原因是,在另一个循环的第一次迭代中,总是会附加一个空字符串。在这个循环中不再是这种情况。

尽管您没有在问题的评论部分中指出这一点,但您表示,要保留空格字符而不是被丢弃是可取的。在这种情况下,您不应使用 操作员/code> 用于阅读输入,一次读取一个单词,但您应该使用 std :: getline ,一次读取一行:

string Read(string& file) {
    ifstream in;
    string text;
    string s;
    in.open(file, ios::in);
    while ( getline( in, s ) ) {
        text.append( s );
        text.append( "\n" );
    }
    return text; 
}

The loop

while (!in.eof()) {
    text.append(s);
    in >> s;
}

is wrong, because the condition while (!in.eof()) may be false even when the previous statement in >> s succeeded. It would be better to write while (!in.fail()) instead of while (!in.eof()).

However, it would be clearer and slightly more efficient to write the loop like this:

while ( in >> s ) {
    text.append(s);
}

This loop condition indirectly uses in.operator bool(), which is equivalent to !in.fail().

The reason why this loop is a bit more efficient than the other loop is that in the first iteration of the other loop, an empty string was always appended. This is no longer the case in this loop.

Although you did not state this in the question, in the comments section of your question, you stated that it would be preferable for the whitespace characters to be retained instead of being discarded. In that case, you should not be using operator >> for reading input, which reads one word at a time, but you should rather be using std::getline, which reads one line at a time:

string Read(string& file) {
    ifstream in;
    string text;
    string s;
    in.open(file, ios::in);
    while ( getline( in, s ) ) {
        text.append( s );
        text.append( "\n" );
    }
    return text; 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文