2016-01-12 2 views
2

Если у меня есть огромный файл (например, 1 ТБ или любой размер, который не помещается в ОЗУ. Файл хранится на диске). Он ограничен пространством. А моя оперативная память - всего 8 ГБ. Могу ли я прочитать этот файл в ifstream? Если нет, то как читать блок файла (например, 4 ГБ)?Как читать огромный файл в C++

+0

Как это ограничено? Это текстовый текст? Вы можете читать строки за раз? – nicomp

+1

@nicomp Я сомневаюсь, что у вас может быть текстовый файл размером 1 ТБ. –

+0

Невозможно. Вы не можете поместить 1 ТБ в любую ОЗУ меньше, чем это. Если вы хотите извлечь данные из этого файла, это может быть возможно. –

ответ

6

Есть несколько вещей, которые вы можете сделать.

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

ifstream bigFile("mybigfile.dat"); 
constexpr size_t bufferSize = 1024 * 1024 * 1024; 
unique_ptr<char[]> buffer(new char[bufferSize]); 
while (bigFile) 
{ 
    bigFile.read(buffer.get(), 1024 * 1024 * 1024); 
    // process data in buffer 
} 

Другим решением является отображение файла в память. Большинство операционных систем позволяют вам отображать файл в память, даже если он больше физического объема памяти, который у вас есть. Это работает, потому что операционная система знает, что каждая страница памяти, связанная с файлом, может быть отображена и отключена по требованию: когда вашей программе нужна определенная страница, ОС будет считывать ее из файла в память вашего процесса и заменять страницу, не используется некоторое время.

Однако это может работать, только если файл меньше максимального объема памяти, который теоретически может использовать ваш процесс. Это не проблема с 1TB-файлом в 64-битном процессе, но он не будет работать в 32-разрядном процессе.

Также be aware of the spirits that you're summoning. Отображение памяти - это не то же самое, что чтение с него. Если файл неожиданно усечен из другой программы, ваша программа, скорее всего, выйдет из строя. Если вы измените данные, возможно, у вас закончится нехватка памяти, если вы не сможете сохранить обратно на диск. Кроме того, алгоритм вашей операционной системы для подкачки в памяти и из памяти может не вести себя так, чтобы вы значительно выигрывали. Из-за этих неопределенностей я бы рассмотрел отображение файла только в том случае, если его чтение в кусках с использованием первого решения не может работать.

В Linux/OS X вы использовали бы для этого mmap. В Windows вы должны открыть файл, а затем использовать CreateFileMapping, затем MapViewOfFile.

+0

Сторона примечания: обычная ошибка; не тестируя операцию потока: 'while (bigFile) {bigFile.read (...); ...} ' –

0

Вы можете использовать fread

char buffer[size]; 
fread(buffer, size, sizeof(char), fp); 

Или, если вы хотите использовать C++ fstreams вы можете использовать read, как buratino сказал.

Также имейте в виду, что вы можете открыть файл независимо от его размера, идея состоит в том, чтобы открыть его и прочитать его в патронах, которые вписываются в вашу оперативную память.

+1

Он спросил о 'ifstream'. Я считаю, что более релевантный вызов функции будет [читать] (http://www.cplusplus.com/reference/istream/istream/read/) – buratino

+0

Я прочитал fread doc. Поэтому, если я использую 'FILE * pFile; pFile = fopen ("myfile.txt", "rb"); 'и myfile.txt не могут быть помещены в ОЗУ, могу ли я открыть его таким образом? – ZigZagZebra

+1

fopen не загружает файл в ram, поэтому да, вы должны быть в состоянии сделать это без проблем. – marian0

1

Более авансы Подход является вместо чтения всего файла или его куски в памяти вы можете отобразить его в память, используя специфичные для платформы API:

Под окнами: CreateFileMapping(), MapViewOfFile()

Под linux: open (2)/creat (2), shm_open, mmap

вам нужно будет скомпилировать 64-битное приложение, чтобы оно работало.

для получения более подробной информации смотрите здесь: CreateFileMapping, MapViewOfFile, how to avoid holding up the system memory

2

Уверен, что вам не нужно хранить весь файл в памяти. Обычно нужно читать и обрабатывать файл кусками. Если вы хотите использовать ifstream, вы можете сделать что-то вроде этого:

ifstream is("/path/to/file"); 
char buf[4096]; 
do { 
    is.read(buf, sizeof(buf)); 
    process_chunk(buf, is.gcount()); 
} while(is); 
Смежные вопросы