簡體   English   中英

使用c ++讀取文本文件最優雅的方法是什么?

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

我想用c ++將文本文件的全部內容讀入std::string對象。

使用Python,我可以寫:

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

它非常簡單而優雅。 我討厭丑陋的東西,所以我想知道 - 用C ++讀取文本文件最優雅的方法是什么? 謝謝。

有很多方法,你選擇哪種方式最適合你。

讀入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。

這個主題還有另一個主題。

我的解決方案來自這個線程(兩個單行):

很好(見米蘭的第二個解決方案):

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

和快:

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

你似乎把優雅說成是“小代碼”的明確屬性。 這在某種程度上是主觀的。 有人會說省略所有錯誤處理並不是很優雅。 有人會說,你立即理解的清晰緊湊的代碼是優雅的。

編寫您自己的單行函數/方法,讀取文件內容,但在表面下使其嚴謹和安全,您將涵蓋優雅的兩個方面。

祝一切順利

/羅伯特·

但要注意一個c ++ - 字符串(或更具體的:一個STL字符串)就像一個能夠容納一串任意長度的C字符串一樣少 - 當然不是!

看看成員max_size(),它給出了字符串可能包含的最大字符數。 這是一個實現定義的數字,可能無法在不同平台之間移植。 Visual Studio為字符串提供了大約4gig的值,其他的可能只給你64k,在64Bit平台上它可能會給你一些非常大的東西! 這取決於當然通常你會在達到4gig限制之前的很長一段時間內由於內存耗盡而遇到bad_alloc異常......

BTW:max_size()也是其他STL容器的成員! 它將為您提供此容器(理論上)能夠容納的特定類型(您為其設備容器)的最大元素數量。

因此,如果您正在閱讀未知來源的文件,您應該:
- 檢查其大小並確保它小於max_size()
- 捕獲並處理bad_alloc-exceptions

還有一點:為什么你熱衷於將文件讀入字符串? 我期望通過逐步解析它或其他東西來進一步處理它,對嗎? 因此,不是將其讀入字符串,而是將其讀入字符串流(基本上只是字符串的一些語法糖)並進行處理。 但是你也可以直接從文件中進行處理。 因為如果正確編程,字符串流可以無縫地由文件流替換,即由文件本身替換。 或者通過任何其他輸入流,它們都共享相同的成員和操作符,因此可以無縫地互換!

對於處理本身:編譯器也可以自動化很多! E. g。 假設您想要對字符串進行標記。 定義適當的模板時,請執行以下操作:
- 從文件(或字符串或任何其他輸入流)讀取
- 對內容進行標記
- 將所有找到的令牌推入STL容器
- 按字母順序對標記進行排序
- 消除任何雙重值
所有(!!)都可以在單個(!)的C ++行代碼中實現 - 代碼(放棄模板本身和錯誤處理)! 它只是函數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只返回一個字符串,這樣你就不必傳入一個緩沖區字符串。然后,測試看看是否編譯器在返回時優化副本。)

但是,這看起來可能會好一些(並且速度要慢得多):


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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM