Я должен скопировать файл в строку. Я должен некоторым образом предварительно выделить память для того строкового объекта и способа непосредственно считать содержание файла в память той строки?
std :: string
имеет метод .reserve
для предварительного выделения.
std::string s;
s.reserve(1048576); // reserve 1 MB
read_file_into(s);
Это должно быть все, что вам нужно:
ostringstream os;
ifstream file("name.txt");
os << file.rdbuf();
string s = os.str();
Читает символы из файла
и вставляет их в поток строк. После этого создается строка, созданная за кулисами. Обратите внимание, что я попал в следующую ловушку: использование оператора извлечения пропустит начальные пробелы. Вы должны использовать оператор вставки, как указано выше, или использовать манипулятор noskipws
:
// Beware, skips initial whitespace!
file >> os.rdbuf();
// This does not skip it
file >> noskipws >> os.rdbuf();
Эти функции описываются как чтение потока посимвольно (хотя не уверен, какие оптимизации здесь возможны), i не рассчитал их время, чтобы определить их скорость.
Это не столько ответ сам по себе, сколько своего рода комментарий/резюме/сравнение пары других ответов (а также быстрая демонстрация того, почему я рекомендовал стиль кода, который @Johannes - litb приводит в своем ответе). Поскольку @sbi опубликовал альтернативу, которая выглядит довольно хорошо, и (особенно) позволяет избежать дополнительного копирования, связанного с чтением в строковый поток, а затем использованием члена .str()
для получения строки, я решил написать быстрое сравнение этих двух вариантов:
[ Edit: Я добавил третий тестовый пример, используя istreambuf_iterator
-базированный код @Tyler McHenry, и добавил строку для вывода длины каждой прочитанной строки, чтобы убедиться, что оптимизатор не оптимизировал чтение, поскольку результат никогда не использовался]
[ Edit2: And now, code from Martin York has been added as well as well...]
#include <fstream>
#include <sstream>
#include <string>
#include <iostream>
#include <iterator>
#include <time.h>
int main() {
std::ostringstream os;
std::ifstream file("equivs2.txt");
clock_t start1 = clock();
os << file.rdbuf();
std::string s = os.str();
clock_t stop1 = clock();
std::cout << "\ns.length() = " << s.length();
std::string s2;
clock_t start2 = clock();
file.seekg( 0, std::ios_base::end );
const std::streampos pos = file.tellg();
file.seekg(0, std::ios_base::beg);
if( pos!=std::streampos(-1) )
s2.reserve(static_cast<std::string::size_type>(pos));
s2.assign(std::istream_iterator<char>(file), std::istream_iterator<char>());
clock_t stop2 = clock();
std::cout << "\ns2.length = " << s2.length();
file.clear();
std::string s3;
clock_t start3 = clock();
file.seekg(0, std::ios::end);
s3.reserve(file.tellg());
file.seekg(0, std::ios::beg);
s3.assign((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
clock_t stop3 = clock();
std::cout << "\ns3.length = " << s3.length();
// New Test
std::string s4;
clock_t start4 = clock();
file.seekg(0, std::ios::end);
s4.resize(file.tellg());
file.seekg(0, std::ios::beg);
file.read(&s4[0], s4.length());
clock_t stop4 = clock();
std::cout << "\ns4.length = " << s3.length();
std::cout << "\nTime using rdbuf: " << stop1 - start1;
std::cout << "\nTime using istream_iterator: " << stop2- start2;
std::cout << "\nTime using istreambuf_iterator: " << stop3 - start3;
std::cout << "\nTime using read: " << stop4 - start4;
return 0;
}
Теперь впечатляющая часть - результаты. Сначала с VC++ (если кому интересно, код Мартина достаточно быстрый, я увеличил размер файла, чтобы получить значимое время для него):
s.length() = 7669436
s2.length = 6390688
s3.length = 7669436
s4.length = 7669436
Время использования rdbuf: 184
Время использования istream_iterator: 1332
Время использования istreambuf_iterator: 249
Время использования read: 48
Затем с gcc (cygwin):
s.length() = 8278035
s2.length = 6390689
s3.length = 8278035
s4.length = 8278035
Время использования rdbuf: 62
Время использования istream_iterator: 2199
Время использования istreambuf_iterator: 156
Время использования read: 16
[ конец правки - выводы остаются, хотя победитель изменился - код Мартина явно самый быстрый. ]
Результаты вполне согласуются в отношении того, кто быстрее и медленнее. Единственное несоответствие заключается в том, насколько намного быстрее или медленнее один код по сравнению с другим. Хотя размещение одинаковое, разница в скорости намного больше у gcc, чем у VC++.
Ради забавы, вот еще один способ сделать это:
// Beware, brain-compiled code ahead!
std::ifstream ifs( /* ... */ );
if( !ifs.good() ) return; // whatever
std::string str;
ifs.seekg( 0, std::ios_base::end );
const std::streampos pos = ifs.tellg();
ifs.seekg( 0, std::ios_base::beg );
if( pos!=std::streampos(-1) ) // can get stream size?
str.reserve(static_cast<std::string::size_type>(pos));
str.assign( std::istream_iterator<char>(ifs)
, std::istream_iterator<char>() );
Надеюсь, я не слишком сильно провалился.
Похоже, вы спрашиваете, как выполнить операцию типа CString::GetBuffer, ReleaseBuffer со строкой std::string.
Я не знаю никакого способа сделать это напрямую, простым способом было бы просто создать необработанный буфер в стиле C, читать в буфер, затем скопировать буфер в std::string, используя assign или что-то еще. Конечно, вам придется беспокоиться о проблемах выхода за пределы буфера и т.д., также я бы использовал std::autoptr для управления указателем необработанного буфера, чтобы исключить деаллокацию при исключении и т.д. Это немного проще, чем использование stringstream и т.д. Если нужно, я могу предоставить пример.
Devin Ellingson