Каков наилучший способ прочитать весь файл в std :: string в C ++?

Вы должны обязательно использовать пакетные скрипты для автоматизации этих процессов. Я разделяю с вами упрощенную версию собственного скрипта-строителя. Моя собственная среда намного сложнее, поэтому я написал этот скрипт для вас легко.

Его использование довольно простое.

builder . -64bit -Debug

Значит, исходный код находится в текущем каталоге, а конфигурация компиляции - 64-битная версия отладки.

Вам нужно всего лишь изменить глобальные переменные конфигурации в скрипте, которые указывают визуальную студию и cmake.

SET VISUAL_STUDIO_9_HOME =

SET CMAKE_HOME =

@echo off

rem ===== Usage
rem builder c:\workspace\project1 -32bit -Release
rem builder . -64bit -Debug

rem Global configuration variables. Should be update based on your system
SET VISUAL_STUDIO_9_HOME=c:\Program Files\Microsoft Visual Studio 9.0
SET CMAKE_HOME=c:\Documents and Settings\stumk\My Documents\toolkit\cmake

rem First parameter is project folder path
SET PROJECT_DIR=%1

rem Add executables into path
rem Only add them once
if NOT DEFINED SETENV  SET SETENV=0
if %SETENV% EQU 0 SET PATH=%CMAKE_HOME%\bin;%VISUAL_STUDIO_9_HOME%\Common7\Tools;%PATH%
SET SETENV=1

rem Go to project director
cd %PROJECT_DIR%

rem Create build folder, don't mess the source code with visual studio project files
md build

rem Go to build folder
cd build\
   rem Set visual studio environment variables
   call vsvars32.bat 

   rem Second parameter defines 32 bit or 64 bit compilation
   if "%2"=="-32bit" (
       cmake.exe .. -G "Visual Studio 9 2008"
   )
   if "%2"=="-64bit" (
       cmake.exe .. -G "Visual Studio 9 2008 Win64"
   )

   rem Third parameter defines debug or release compilation
   if "%3"=="-Debug" (
           cmake.exe --build . --target ALL_BUILD --config Debug
   )
   if "%3"=="-Release" (
           cmake.exe --build . --target ALL_BUILD --config Release
   )

   rem Go to source code directory and finalize script
   cd ..

@echo on
147
задан Peter Mortensen 4 March 2017 в 05:12
поделиться

8 ответов

Используйте

#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 функция, как спросили.

16
ответ дан Peter Mortensen 4 March 2017 в 05:12
поделиться

Что-то вроде этого не должно быть слишком плохим:

void slurp(std::string& data, const std::string& filename, bool is_binary)
{
    std::ios_base::openmode openmode = ios::ate | ios::in;
    if (is_binary)
        openmode |= ios::binary;
    ifstream file(filename.c_str(), openmode);
    data.clear();
    data.reserve(file.tellg());
    file.seekg(0, ios::beg);
    data.append(istreambuf_iterator<char>(file.rdbuf()), 
                istreambuf_iterator<char>());
}

преимущество здесь состоит в том, что мы делаем резерв сначала, таким образом, мы не должны будем выращивать строку, поскольку мы читаем вещи в. Недостаток - то, что мы делаем это символ символом. Более умная версия могла захватить целое чтение buf и затем назвать потерю значимости.

3
ответ дан Matt Price 4 March 2017 в 05:12
поделиться

И самое быстрое (что я знаю о, обесценивая файлы с отображенной памятью):

std::string str(static_cast<std::stringstream const&>(std::stringstream() << in.rdbuf()).str());

Это требует дополнительного заголовка <sstream> для строкового потока. (Эти static_cast необходимо с тех пор operator << возвраты простое ostream&, но мы знаем, что в действительности it’s stringstream&, таким образом, бросок безопасен.)

Разделение в несколько строк, перемещая временный файл в переменную, мы получаем более читаемый код:

std::string slurp(std::ifstream& in) {
    std::stringstream sstr;
    sstr << in.rdbuf();
    return sstr.str();
}

Или, еще раз в одной строке:

std::string slurp(std::ifstream& in) {
    return static_cast<std::stringstream const&>(std::stringstream() << in.rdbuf()).str();
}
121
ответ дан Jean-François Fabre 4 March 2017 в 05:12
поделиться

Самый короткий вариант: , Живой На Coliru

std::string str(std::istreambuf_iterator<char>{ifs}, {});

, Это требует заголовка <iterator>.

были некоторые отчеты, что этот метод медленнее, чем предварительное выделение строки и использование std::istream::read. Однако на современном компиляторе с оптимизациями, включенными, это больше, кажется, не имеет место, хотя относительная производительность различных методов, кажется, высоко зависимый компилятора.

43
ответ дан Konrad Rudolph 4 March 2017 в 05:12
поделиться

Никогда не пишите в станд.:: символ константы строки * буфер. Никогда! Выполнение так является серьезной ошибкой.

Резерв () располагают с интервалами для целой строки в Вашем станд.:: строка, считайте блоки из своего файла разумного размера в буфер и добавьте () его. То, насколько большой блоки должны быть, зависит от Вашего входного размера файла. Я вполне уверен, все другие портативные и совместимые STL механизмы сделают то же (все же может выглядеть более симпатичным).

3
ответ дан Peter Mortensen 4 March 2017 в 05:12
поделиться

Можно использовать 'станд.:: getline' функция, и определяют 'eof' как разделитель. Получающийся код немного неясен хотя:

std::string data;
std::ifstream in( "test.txt" );
std::getline( in, data, std::string::traits_type::to_char_type( 
                  std::string::traits_type::eof() ) );
2
ответ дан Martin Cote 4 March 2017 в 05:12
поделиться

См. этот ответ по подобному вопросу.

Для Вашего удобства, я повторно отправляю решение 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);
}

Это решение закончилось приблизительно в на 20% более быстрое время выполнения, чем другие ответы, представленные здесь при взятии среднего числа 100 выполнений против текста Моби Дика (1.3M). Не плохо для портативного решения C++, я хотел бы видеть результаты mmap'ing файл ;)

48
ответ дан Deduplicator 4 March 2017 в 05:12
поделиться

Вот версия, пользующаяся новой библиотекой файловой системы с довольно устойчивой проверкой ошибок:

#include <cstdint>
#include <exception>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <string>

namespace fs = std::filesystem;

std::string loadFile(const char *const name);
std::string loadFile(const std::string &name);

std::string loadFile(const char *const name) {
  fs::path filepath(fs::absolute(fs::path(name)));

  std::uintmax_t fsize;

  if (fs::exists(filepath)) {
    fsize = fs::file_size(filepath);
  } else {
    throw(std::invalid_argument("File not found: " + filepath.string()));
  }

  std::ifstream infile;
  infile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
  try {
    infile.open(filepath.c_str(), std::ios::in | std::ifstream::binary);
  } catch (...) {
    std::throw_with_nested(std::runtime_error("Can't open input file " + filepath.string()));
  }

  std::string fileStr;

  try {
    fileStr.resize(fsize);
  } catch (...) {
    std::stringstream err;
    err << "Can't resize to " << fsize << " bytes";
    std::throw_with_nested(std::runtime_error(err.str()));
  }

  infile.read(fileStr.data(), fsize);
  infile.close();

  return fileStr;
}

std::string loadFile(const std::string &name) { return loadFile(name.c_str()); };
1
ответ дан 23 November 2019 в 21:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: