65

std::stringテキストファイルのコンテンツ全体をC++でオブジェクトに読み込みたいのですが。

Pythonを使用すると、次のように書くことができます。

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

とてもシンプルでエレガントです。私は醜いものが嫌いなので、知りたいのですが、C ++でテキストファイルを読むための最もエレガントな方法は何ですか?ありがとう。

4

5 に答える 5

135

多くの方法があります。あなたにとって最もエレガントなものを選んでください。

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>());

stringstream を使用して文字列に変換します。

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

file.txt は単なる例です。バイナリ ファイルでもすべて正常に機能します。ifstream コンストラクターで ios::binary を使用していることを確認してください。

于 2008-10-12T11:06:34.907 に答える
12

この件については別のスレッドがあります。

このスレッドからの私の解決策(両方ともワンライナー):

素晴らしい(ミラノの2番目の解決策を参照):

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

そして速い:

string str(static_cast<stringstream const&>(stringstream() << ifs.rdbuf()).str());
于 2008-10-12T14:36:49.460 に答える
4

あなたはエレガンスを「小さなコード」の明確な特性として語っているようです。もちろん、これはある程度主観的です。すべてのエラー処理を省略するのはあまり洗練されていないと言う人もいます。すぐに理解できる明確でコンパクトなコードはエレガントだと言う人もいます。

ファイルの内容を読み取る独自のワンライナー関数/メソッドを作成しますが、表面下で厳密で安全なものにすると、エレガンスの両方の側面をカバーできます。

ではごきげんよう

/ロバート

于 2008-10-12T11:06:02.257 に答える
2

ただし、C++ 文字列 (より具体的には STL 文字列) は、任意の長さの文字列を保持できる C 文字列と同じくらい小さいことに注意してください。もちろん違います!

文字列に含まれる最大文字数を示すメンバー max_size() を見てください。これは実装定義の数値であり、異なるプラットフォーム間で移植できない場合があります。Visual Studio では、文字列に対して約 4 ギガの値が得られますが、他のものでは 64k しか得られず、64 ビット プラットフォームでは非常に大きな値が得られる可能性があります。それは状況によって異なりますが、もちろん通常は、4 ギガの制限に達する前に、メモリ不足のために bad_alloc-exception が発生します...

ところで: max_size() は他の STL コンテナのメンバーでもあります! このコンテナが(理論的に)保持できる特定のタイプ(コンテナをインスタンス化したもの)の要素の最大数を提供します。

したがって、出所がわからないファイルから読み取る場合は、次のことを行う必要があります。
- サイズを確認し、max_size() より小さいことを確認します
- bad_alloc-exceptions をキャッチして処理します

もう 1 つのポイント: なぜファイルを文字列に読み込むことに熱心なのですか? それを段階的に解析することで、さらに処理することを期待していますよね?したがって、文字列に読み込む代わりに、文字列ストリーム (基本的には文字列の構文糖衣) に読み込んで処理を行うこともできます。ただし、ファイルから直接処理を行うこともできます。適切にプログラムされていれば、文字列ストリームはシームレスにファイルストリーム、つまりファイル自体に置き換えることができるからです。または、他の入力ストリームによっても、それらはすべて同じメンバーと演算子を共有するため、シームレスに交換できます!

そして、処理自体について: コンパイラーによって自動化できるものもたくさんあります! 例)文字列をトークン化するとします。適切なテンプレートを定義するときは、次のアクションを実行します:
- ファイル (または文字列またはその他の入力ストリーム)
から読み取る - コンテンツ
をトークン化する - 見つかったすべてのトークンを STL コンテナーにプッシュする-
トークンをアルファベット順に並べ替える
- すべての double 値
を削除する(!!) C++ コードの 1 行 (!) で実現できます (テンプレート自体とエラー処理は別として)! 関数 std::copy() を 1 回呼び出すだけです。「トークン イテレータ」をググるだけで、私の言いたいことがわかるでしょう。したがって、これは単にファイルから読み取るよりもさらに「エレガント」に見えます...

于 2010-09-23T11:41:07.353 に答える
0

Milan の 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";
}
于 2008-10-12T14:24:11.467 に答える