파일을로 읽는 방법 std::string
, 즉 전체 파일을 한 번에 읽는 방법은 무엇입니까?
텍스트 또는 이진 모드는 호출자가 지정해야합니다. 솔루션은 표준을 준수하고 휴대 가능하며 효율적이어야합니다. 문자열 데이터를 불필요하게 복사해서는 안되며 문자열을 읽는 동안 메모리 재 할당을 피해야합니다.
의 파일 크기를 찍으하는 것이 작업을 수행하는 한 가지 방법은 크기를 조정 std::string
하고 fread()
에 std::string
‘의 const_cast<char*>()
‘에드 data()
. 이를 위해서는 std::string
의 데이터가 표준에 필요하지 않은 연속적이어야하지만 모든 알려진 구현의 경우 인 것 같습니다. 더 나쁜 것은, 파일을 텍스트 모드에서 읽는 경우 std::string
의 크기가 파일의 크기와 같지 않을 수 있습니다.
완전히 올바른, 표준 준수 및 휴대용 솔루션을 사용하여 구성 할 수 std::ifstream
의를 rdbuf()
에 std::ostringstream
와에 거기에서 std::string
. 그러나 이것은 문자열 데이터를 복사하거나 메모리를 불필요하게 재 할당 할 수 있습니다.
- 모든 관련 표준 라이브러리 구현이 불필요한 오버 헤드를 피할 수있을만큼 똑똑합니까?
- 다른 방법이 있습니까?
- 이미 원하는 기능을 제공하는 숨겨진 부스트 기능이 누락 되었습니까?
void slurp(std::string& data, bool is_binary)
답변
한 가지 방법은 스트림 버퍼를 별도의 메모리 스트림으로 플러시하고 다음으로 변환하는 것입니다 std::string
.
std::string slurp(std::ifstream& in) {
std::ostringstream sstr;
sstr << in.rdbuf();
return sstr.str();
}
이것은 간결합니다. 그러나 문제에서 언급했듯이 이것은 중복 사본을 수행하며 불행히도이 사본을 얻는 방법은 없습니다.
중복 사본을 피하는 유일한 실제 솔루션은 불행히도 루프에서 수동으로 읽기를 수행하는 것입니다. C ++는 이제 연속 문자열을 보장하므로 다음과 같이 작성할 수 있습니다 (≥C ++ 14).
auto read_file(std::string_view path) -> std::string {
constexpr auto read_size = std::size_t{4096};
auto stream = std::ifstream{path.data()};
stream.exceptions(std::ios_base::badbit);
auto out = std::string{};
auto buf = std::string(read_size, '\0');
while (stream.read(& buf[0], read_size)) {
out.append(buf, 0, stream.gcount());
}
out.append(buf, 0, stream.gcount());
return out;
}
답변
비슷한 질문에 대한 이 답변 을 참조하십시오 .
귀하의 편의를 위해 CTT의 솔루션을 다시 게시하고 있습니다.
string readFile2(const string &fileName)
{
ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);
ifstream::pos_type fileSize = ifs.tellg();
ifs.seekg(0, ios::beg);
vector<char> bytes(fileSize);
ifs.read(bytes.data(), fileSize);
return string(bytes.data(), fileSize);
}
이 솔루션은 Moby Dick (1.3M) 텍스트에 대해 평균 100 회 실행하는 경우 여기에 제시된 다른 답변보다 약 20 % 빠른 실행 시간을 제공합니다. 휴대용 C ++ 솔루션에는 나쁘지 않습니다. 파일을 mmap’ing 한 결과를보고 싶습니다.)
답변
가장 짧은 변형 : Live On Coliru
std::string str(std::istreambuf_iterator<char>{ifs}, {});
헤더가 필요합니다 <iterator>
.
이 방법이 문자열을 미리 할당하고 사용하는 것보다 느리다는보고가있었습니다 std::istream::read
. 그러나 최적화가 활성화 된 최신 컴파일러에서는 더 이상 그렇지 않은 것처럼 보이지만 다양한 방법의 상대적인 성능은 컴파일러에 크게 의존하는 것으로 보입니다.
답변
사용하다
#include <iostream>
#include <sstream>
#include <fstream>
int main()
{
std::ifstream input("file.txt");
std::stringstream sstr;
while(input >> sstr.rdbuf());
std::cout << sstr.str() << std::endl;
}
또는 아주 가까운 무언가. 직접 확인하는 stdlib 참조가 없습니다.
예, slurp
요청대로 함수를 작성하지 않았다는 것을 이해 합니다.
답변
C ++ 17 (std :: filesystem)이있는 경우이 방법도 있습니다 ( 및 std::filesystem::file_size
대신 파일 크기를 가져옵니다 ).seekg
tellg
#include <filesystem>
#include <fstream>
#include <string>
namespace fs = std::filesystem;
std::string readFile(fs::path path)
{
// Open the stream to 'lock' the file.
std::ifstream f(path, std::ios::in | std::ios::binary);
// Obtain the size of the file.
const auto sz = fs::file_size(path);
// Create a buffer.
std::string result(sz, '\0');
// Read the whole file into the buffer.
f.read(result.data(), sz);
return result;
}
참고 : 당신이 사용해야 할 수도 있습니다 <experimental/filesystem>
및 std::experimental::filesystem
표준 라이브러리가 아직 완전히 ++ 17 C를 지원하지 않는 경우. 당신은 교체해야 할 수도 있습니다 result.data()
로 &result[0]
는 지원하지 않는 경우 const가 아닌 표준 : : basic_string 데이터를 .
답변
를 사용하여 답변에 직접 의견을 올릴만한 명성이 없습니다 tellg()
.
양해하여 주시기 바랍니다 tellg()
반환 할 수 에러시 -1. tellg()
할당 매개 변수로 결과를 전달하는 경우 결과를 먼저 확인해야합니다.
문제의 예 :
...
std::streamsize size = file.tellg();
std::vector<char> buffer(size);
...
위의 예에서 tellg()
오류가 발생하면 -1을 반환합니다. 부호있는 (즉, 결과 tellg()
)과 부호없는 (즉, vector<char>
생성자에 대한 인수) 사이의 암시 적 캐스팅은 벡터에 매우 많은 바이트를 잘못 할당하게 됩니다. (아마도 4294967295 바이트 또는 4GB)
위의 설명을 위해 paxos1977의 답변 수정 :
string readFile2(const string &fileName)
{
ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);
ifstream::pos_type fileSize = ifs.tellg();
if (fileSize < 0) <--- ADDED
return std::string(); <--- ADDED
ifs.seekg(0, ios::beg);
vector<char> bytes(fileSize);
ifs.read(&bytes[0], fileSize);
return string(&bytes[0], fileSize);
}
답변
이 솔루션은 rdbuf () 기반 메소드에 오류 점검을 추가합니다.
std::string file_to_string(const std::string& file_name)
{
std::ifstream file_stream{file_name};
if (file_stream.fail())
{
// Error opening file.
}
std::ostringstream str_stream{};
file_stream >> str_stream.rdbuf(); // NOT str_stream << file_stream.rdbuf()
if (file_stream.fail() && !file_stream.eof())
{
// Error reading file.
}
return str_stream.str();
}
원래 방법에 오류 확인을 추가하는 것이 예상만큼 사소하지 않기 때문에이 답변을 추가하고 있습니다. 원래 메소드는 문자열 스트림의 삽입 연산자 ( str_stream << file_stream.rdbuf()
)를 사용합니다. 문제는 문자가 삽입되지 않을 때 문자열 스트림의 페일 비트를 설정한다는 것입니다. 오류로 인한 것일 수도 있고 파일이 비어 있기 때문일 수도 있습니다. 페일 비트를 검사하여 실패를 확인하면 빈 파일을 읽을 때 오 탐지가 발생합니다. 파일이 비어 있기 때문에 문자를 삽입하지 않는 합법적 인 실패와 문자를 삽입하는 “실패”를 어떻게 명확하게합니까?
빈 파일을 명시 적으로 검사한다고 생각할 수도 있지만 더 많은 코드와 관련 오류 검사입니다.
str_stream.fail() && !str_stream.eof()
삽입 조작이 eofbit (ostringstream 또는 ifstream)를 설정하지 않으므로 실패 조건 점검이 작동하지 않습니다.
따라서 해결책은 작업을 변경하는 것입니다. ostringstream의 삽입 연산자 (<<)를 사용하는 대신, eofbit를 설정하는 ifstream의 추출 연산자 (>>)를 사용하십시오. 그런 다음 실패 조건을 확인하십시오 file_stream.fail() && !file_stream.eof()
.
중요한 file_stream >> str_stream.rdbuf()
것은 합법적 인 오류가 발생 했을 때 (사양에 대한 나의 이해에 따라) eofbit를 설정해서는 안됩니다. 즉, 위의 점검은 합법적 인 오류를 감지하기에 충분하다는 것을 의미합니다.