Development Tip

C ++로 텍스트 파일을 읽는 가장 우아한 방법은 무엇입니까?

yourdevel 2020. 12. 14. 20:56
반응형

C ++로 텍스트 파일을 읽는 가장 우아한 방법은 무엇입니까?


텍스트 파일의 전체 내용을 std::stringC ++ 개체 로 읽고 싶습니다 .

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

벡터로 <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-exception이 발생합니다.

BTW : 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

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...


I like Milan's char* way, but with 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.)

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

참고URL : https://stackoverflow.com/questions/195323/what-is-the-most-elegant-way-to-read-a-text-file-with-c

반응형