![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Обработка текстовых файлов больших размеров (2 - 3 ГГб) [D7, WinXP]
bsframer © (2006-04-26 08:59:00)Здраствуйте, Уважаемые. Может вопрос и глупый, но мучаюсь уже второй день. Есть текстовый файл большого размера (2-3 ГГб), строки порядка 200 символов. Вопрос, как можно провести в нем сортировку по возрастанию (убыванию)? Пробовал ReadLn, BlockRead, TFileStream - медленно (нужно чтоб 50 МГб примерно за 5 минут пробегало). Через TStringList можно (100 МГб - 2,5 минуты), но в него влазит порядка 500 МГб (Оперативки 1 ГГб), дальше сообщение Out of Memory и стопор. Разрезание файла на куски думал, но это геморойно. Слышал про FileMapping, но не знаю как с ним работать и подойдет ли он вообще. Может есть какой способ, чтоб оперативки меньше жрало и работало быстрее, или я не так пробовал?
SYSCON (2006-05-02 09:30:00) [1]А виндовая Sort.exe для этой задачи не подойдет?
GrayFace (2006-04-29 08:12:00) [2]> Сергей М. © (28.04.06 11:16) [29]
> О какой разности смещений можно говорить для последней строки?
Ежу понятно, что для нее придется сделать исключение - хранить длину или вычислить смещение, на котором бы находилась следующая строка. Наверное, лучше второе.
han_malign (2006-04-28 11:47:00) [3]
> Слышал про FileMapping, но не знаю как с ним работать и подойдет ли он вообще.
- File mapping поможет мало, все равно окно больше максимального доступного не фрагментированного диапазона виртальных адресов не сделаешь(MapViewOfFile), т.е. примерно такое же ограничение как StringList...
Но для общего развития:
type
TFileMappingData = class
private
F_hFile: THandle;
F_hMap: THandle;
F_sFileName: string;
F_pData: pointer;
F_cbSize: integer;
F_dwError: DWORD;
public
constructor Create(const aFileName: string= '');
destructor Destroy; override;
function Reset(const aFileName: string= ''): boolean;
property Data: pointer read F_pData;
property Size: integer read F_cbSize;
property Error: DWORD read F_dwError;
end;
implementation
constructor TFileMappingData.Create(const aFileName: string= '');
begin
F_hFile:=INVALID_HANDLE_VALUE;
Reset(aFileName);
end;
destructor TFileMappingData.Destroy;
begin
Reset;
end;
function TFileMappingData.Reset(const aFileName: string= ''): boolean;
begin
Result:=F_pData<>nil;
if(CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, PChar(aFileName), Length(aFileName), PChar(F_sFileName), Length(F_sFileName))=2)
then exit;
if(F_pData <> nil)then UnmapViewOfFile(F_pData);
if(F_hMap <> 0)then CloseHandle(F_hMap);
if(F_hFile <> INVALID_HANDLE_VALUE)then CloseHandle(F_hFile);
F_pData:=nil;
F_hMap:=0;
F_hFile:= INVALID_HANDLE_VALUE;
Result:= true; F_dwError:= ERROR_NO_DATA;
if(aFileName <> '')then begin
F_hFile:= CreateFile(PChar(aFileName),GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if(F_hFile <> INVALID_HANDLE_VALUE)then begin
F_hMap:= CreateFileMapping(F_hFile, nil, PAGE_READONLY, 0, 0, nil);
if(F_hMap<>0)then begin
F_pData:= MapViewOfFile(F_hMap, FILE_MAP_READ, 0, 0, 0);
if(F_pData <> nil)then begin
F_cbSize:= GetFileSize(F_hFile, nil);
F_sFileName:= aFileName;
F_dwError:= NO_ERROR;
exit;
end else F_dwError:=GetLastError;
CloseHandle(F_hMap);
end else F_dwError:=GetLastError;
CloseHandle(F_hMap);
end else F_dwError:=GetLastError;
Result:=false;
end else begin
F_sFileName:='';
end;
end;
- мапирует файл "целиком"(пытается), только для чтения...
Сергей М. (2006-04-28 11:16:00) [4]
> GrayFace © (28.04.06 11:08) [28]
> хранить размер не нужно
> разность смещений
О какой разности смещений можно говорить для последнейстроки ?
GrayFace (2006-04-28 11:08:00) [5]> Да куда мне это запихать, вся информация будет чуть меньше
> размером чем сам файл.
Длина строк ~ 200 символов, размер файлов = 2-3 GB. Если хранить смещения и первые 4 символа, получаем 3000/200*8=120 MB. Максимальный размер обрабатываемого файла = 2/8*200=50GB. Думаю, достаточно. Конечно, при подобных размерах своп придется подергать.
А хранить размер не нужно. Он = разность смещений - размер перевода строки.
Быструю сортировку см. в TStringList.Sort.
bsframer (2006-04-26 14:41:00) [6]:) а пример кода можно?
Сергей М. (2006-04-26 14:22:00) [7]До 4Гб - тип DWORD.
Классы - на твой вкус.
Можешь вообще их не использовать.
bsframer (2006-04-26 14:15:00) [8]
> читаешь последовательно строки исх.файла, фиксируешь их
> смещение и размер.
> Далее сортируешь полученную таблицу
Сортировка конечно, можно подробнее описать (какие типы и классы использовать)?
Сергей М. (2006-04-26 14:00:00) [9]
> bsframer (26.04.06 13:50) [22]
Тебе сортировка нужна или "пихать" ?
bsframer (2006-04-26 13:59:00) [10]Брать последнюю строчку в Memo (она будет либо полной либо нет) взять ее длинну, удалить. Затем установить указатель в файле на 64 кб - Длинна последней строчки и считывать следующие 64 кб.
bsframer (2006-04-26 13:50:00) [11]Да куда мне это запихать, вся информация будет чуть меньше размером чем сам файл. И еще если я прочитаю потоком 64 кб, мне проще записать их в Memo, он автоматом строки разбивает, я думаю должно быстрее быть чем самому поиск осуществлять.
GrayFace (2006-04-26 13:42:00) [12]Сомневаюсь, что удастся сильно обгонать ReadLn. Кстати, вместе с позициями и длинами строк полезно будет хранить первые несколько символов.
Сергей М. (2006-04-26 13:38:00) [13]Подключить-то можно, но смысла в этом нет.
Без индексирования данных результат будет удручающим.
bsframer (2006-04-26 13:33:00) [14]А через ADO (Microsoft Text Driver) реально подключить и обработать такой файл?
Сергей М. (2006-04-26 12:24:00) [15]
> значит всетаки побайтно брать?
Зачем побайтно ?
Считывай сразу по 64кб и ищи там символы-разделители, учитывая при этом результаты поиска конца последней строки при анализе предыдущих считанных 64кб
bsframer (2006-04-26 11:52:00) [16]Это понятно, значит всетаки побайтно брать? Другова способа нет?
Palladin (2006-04-26 11:31:00) [17]Общепринятый конец у строки там где есть #13 или #10 или #13#10
bsframer (2006-04-26 11:16:00) [18]Неподскажите чем реализовать быстрое считывание строк. TFileStream не знает где конец у строки, Readln медленный, побайтно тоже медленно.
Сергей М. (2006-04-26 10:22:00) [19]Если таки вариант с СУБД не устраивает никаким образом, построить самому индексную таблицу не так уж и сложно - читаешь последовательно строки исх.файла, фиксируешь их смещение и размер.
Далее сортируешь полученную таблицу (теперь обращение к строкам исх.файла - произвольное, а не последовательное) и уже имея ее отсортированную записываешь считываемые из исх.файла соотв.строки в результирующий файл.
Сергей М. (2006-04-26 10:16:00) [20]
> bsframer (26.04.06 09:52) [9]
Подойдет даже FB Embedded