Как читать содержимое файла в istringstream?
Чтобы улучшить чтение производительности из файла, я пытаюсь прочитать весь контент большого (несколько МБ) файлов в памяти, а затем использовать istringstream для доступа к информации.
Мой вопрос в том, что это лучший способ прочитать эту информацию и "импортировать ее" в поток строк? Проблема с этим подходом (см. Ниже) заключается в том, что при создании потока строк буферы копируются, а использование памяти удваивается.
#include <fstream>
#include <sstream>
using namespace std;
int main() {
ifstream is;
is.open (sFilename.c_str(), ios::binary );
// get length of file:
is.seekg (0, std::ios::end);
long length = is.tellg();
is.seekg (0, std::ios::beg);
// allocate memory:
char *buffer = new char [length];
// read data as a block:
is.read (buffer,length);
// create string stream of memory contents
// NOTE: this ends up copying the buffer!!!
istringstream iss( string( buffer ) );
// delete temporary buffer
delete [] buffer;
// close filestream
is.close();
/* ==================================
* Use iss to access data
*/
}
Ответы
Ответ 1
std::ifstream
имеет метод rdbuf()
, который возвращает указатель на filebuf
. Затем вы можете " filebuf
" этот filebuf
в ваш stringstream
:
#include <fstream>
#include <sstream>
int main()
{
std::ifstream file( "myFile" );
if ( file )
{
std::stringstream buffer;
buffer << file.rdbuf();
file.close();
// operations on the buffer...
}
}
РЕДАКТИРОВАТЬ: Как отмечает Мартин Йорк в комментариях, это может быть не самое быстрое решение, так как operator<<
stringstream
operator<<
будет читать символьный файл filebuf. Возможно, вы захотите проверить его ответ, где он использует ifstream
read
ifstream
как вы это делали, и затем установить буфер stringstream
чтобы он указывал на ранее выделенную память.
Ответ 2
OK. Я не говорю, что это будет быстрее, чем чтение из файла
Но это метод, когда вы создаете буфер один раз и после того, как данные считываются в буфер, используйте его напрямую в качестве источника для строкового потока.
N.B. Стоит отметить, что std:: ifstream буферизуется. Он считывает данные из файла в (относительно больших) фрагментах. Операции потока выполняются против буфера, только возвращающегося к файлу для другого, когда требуется больше данных. Поэтому, прежде чем всасывать все данные в память, убедитесь, что это бутылочная горловина.
#include <fstream>
#include <sstream>
#include <vector>
int main()
{
std::ifstream file("Plop");
if (file)
{
/*
* Get the size of the file
*/
file.seekg(0,std::ios::end);
std::streampos length = file.tellg();
file.seekg(0,std::ios::beg);
/*
* Use a vector as the buffer.
* It is exception safe and will be tidied up correctly.
* This constructor creates a buffer of the correct length.
*
* Then read the whole file into the buffer.
*/
std::vector<char> buffer(length);
file.read(&buffer[0],length);
/*
* Create your string stream.
* Get the stringbuffer from the stream and set the vector as it source.
*/
std::stringstream localStream;
localStream.rdbuf()->pubsetbuf(&buffer[0],length);
/*
* Note the buffer is NOT copied, if it goes out of scope
* the stream will be reading from released memory.
*/
}
}
Ответ 3
Это кажется преждевременной оптимизацией для меня. Сколько работы выполняется в процессе обработки. Предполагая, что современный настольный компьютер, а не встроенная система, копирование нескольких МБ данных во время иналинизации довольно дешево, особенно по сравнению с чтением файла с диска в первую очередь. Я хотел бы придерживаться того, что у вас есть, измерить систему, когда она будет завершена, и решить, будет ли потенциальная прибыль от повышения производительности. Конечно, если память плотная, она находится во внутреннем цикле или программе, которая часто вызывает вызов (например, один раз в секунду), который изменяет баланс.
Ответ 4
Еще одна вещь, о которой нужно помнить, заключается в том, что файловый ввод-вывод всегда будет самой медленной операцией. Решение Luc Touraille верное, но есть и другие варианты. Чтение всего файла в память сразу будет намного быстрее, чем отдельные чтения.