Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.15.225.173] |
|
Страницы: (2) [1] 2 все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Ребята как переделать вот этот код - под чтение построчно. Что бы не загружать в память.
var s: TStringList; z, p, q: Integer; begin s := TStringList.Create; s.LoadFromFile('C:\text.txt'); z := 50; while (z > 0) do begin p := random(s.Count); q := random(s.Count); s.Exchange(p, q); dec(z); end; s.SaveToFile('c:\text.txt'); s.Free; end; Начал переделывать вот так (но вот в регуляровкой рандом не дружу): var z, p, q: Integer; ft, ft2: TextFile; s:string; begin if OpenDialog1.Execute then begin AssignFile(ft, OpenDialog1.FileName); Reset(ft); AssignFile(ft2, ExtractFileDir(OpenDialog1.FileName)+'\rez.txt'); Rewrite(ft2); // чтобы создался новый, если нету, или перезаписался с нуля Append(ft2); // чтобы можно было добавлять строки, а не перезаписывать каждый раз begin while not eof(ft) do begin readln(ft,s); ////////////////////////////////////// Вот тут не знаю что дописать ? ////////////////////////////////////// writeln(ft2,s) end; closefile(ft); closefile(ft2); end; end; end; Подскажите кто сможет ? То есть решение задачи: перемешивание строк в текстовом файле размером 500 - 700 мегабайт. |
Сообщ.
#2
,
|
|
|
На SO ты сонм своих однообразных вопросов под женским ником пишешь.
Раздвоение личности мешает разобраться однажды и навсегда? |
Сообщ.
#3
,
|
|
|
Цитата Kirilis2018 @ Rewrite(ft2); // чтобы создался новый, если нету, или перезаписался с нуля Append(ft2); // чтобы можно было добавлять строки, а не перезаписывать каждый раз Так не прокатит. If FileExist(ft2) Then Append(ft2) else Rewrite(ft2); |
Сообщ.
#4
,
|
|
|
Цитата MBo @ На SO ты сонм своих однообразных вопросов под женским ником пишешь. Раздвоение личности мешает разобраться однажды и навсегда? То я с сестрой по очереди. Учим вместе Delphi, потому так (один аккаунт на двоих). Добавлено ^D^ima А как тогда проще сделать ? Подскажите пожалуйста. |
Сообщ.
#5
,
|
|
|
Пока самым оптимальным вариантом вижу такой:
1. Открываем файл со строками в двоичном режиме. 2. Читаем файл побайтно(пословно, если уникод), узнавая где строки начинаются, занося в память (в таблицу) начало каждой новой строки. 3. Создаём массив номеров строк в памяти. 4. Перемешиваем этот массив тем случайным способом. 5. Аккуратно идём по этим перемешаным номерам, понимаем какая строка нужна сюда и двоично читаем её из того файла со смещением из таблицы, пишем в результат. Всё. П.С. тьма двоичных перемещений по файлу со строками всё равно останется. Что весьма печально. Но памяти будет расходоваться крайне мало! |
Сообщ.
#6
,
|
|
|
Цитата Kirilis2018 @ А как тогда проще сделать ? Подскажите пожалуйста. Тогда нужно понимать из чего состоит файл, из строк фиксированной длины или чего-то ещё? |
Сообщ.
#7
,
|
|
|
Цитата ^D^ima @ Тогда нужно понимать из чего состоит файл, из строк фиксированной длины или чего-то ещё? Файл состоит из строк разной длины. Разные предложения и цифры. |
Сообщ.
#8
,
|
|
|
Это самый плохой вариант в данном случаи. Возможно меня коллеги поправят но я думаю что стратегия зсключается в считывании в случайном порядке строк из входящего файла и последовательной записи в исходялий. Для этого нужно составить карту файла и найти смещения и длину всех строк. Данные записать в массив. Массив перемешать и перемещаясь по файлу согласно даному массиву вычитывать файл. Если бы строки былибы фиксированной длины, былобы проще в разы
|
Сообщ.
#9
,
|
|
|
примерно так:
procedure TForm1.Button1Click(Sender: TObject); Type TRec = record SeekBegin:Longint; StringLength:Longint; end; Var FInMap:TextFile; FIn,FOut:File; S:String; StringCount,NumRead:Longint; FileMap:array[0..1000] of TRec; C:array[1..2048] of char; begin assignfile(FInMap,'c:\123.txt'); Reset(FInMap); StringCount:=1; While not eof(FInMap) do Begin Readln(FInMap,s); FileMap[StringCount].SeekBegin:=FileMap[StringCount-1].SeekBegin+FileMap[StringCount-1].StringLength; FileMap[StringCount].StringLength:=Length(s)+2; Inc(StringCount); End; FileMap[StringCount].StringLength:=FileMap[StringCount].StringLength-2; CloseFile(FInMap); //тут перемешиваем FileMap assignfile(FIn,'c:\123.txt'); assignfile(FOut,'c:\321.txt'); Reset(FIn,1); Rewrite(FOut,1); For StringCount:=1 To StringCount-1 do Begin Seek(FIn,FileMap[StringCount].SeekBegin); BlockRead(FIn,C,FileMap[StringCount].StringLength,NumRead); BlockWrite(FOut,C,NumRead); End; CloseFile(FOut); CloseFile(FIn); end; Тут такая особенность работы с текстовыми файлами: Каждая строка заканчивается невидимым символом в блокноте CRLF, поэтому работая через поблочное чтение\запись учитываем 2 байта. Везде кроме последней строки. Так что при перемешивании учитываем такую особенность.Или не перемешивать последнюю сроку или отслеживать самостоятельо данный момент. Возможен вариант когда уже в поблочной записи вставляются эти символы. В коде не отработаен вариант с динамическим масивом FileMap, а его нужно делать по хорошему динамическим иначе может быть вариант когда кол-во строк ыайла выше 1000, или любого другого значения. который мы поставим. Добавлено Ну и да, нет самого перемешивания массива |
Сообщ.
#10
,
|
|
|
Цитата Kirilis2018 @ в регуляровкой рандом не дружу Random() и Randomoze() - http://delphi-help.ru/index.php?option=com...hislah-v-delphi Пример на С++ Builder, сорри, думаю - разберёшься. Или тут помогут переписать. TStringList *src = new TStringList(); // источник TStringList *dst = new TStringList(); // приёмник src->LoadFromFile("src.txt"); int count = src->Count; // начальное количество строк - значение счётчика Randomize(); int pos = Random(count); // случайнаяпозиция строки для копирования while (coumt >= 0) { dst->Add(src->Strings[pos]); // скопировать из источника в приёмник dst->Delete(pos); // УДАЛИТЬ строку из источника, она уже есть в приёмнике count--; // уменьшить счётчик pos = Random(count); // получить новую случайную позицию в мсточнике } dst->SaveToFile("dst.txt"); detete src; delete dst; |
Сообщ.
#11
,
|
|
|
Цитата Kirilis2018 @ решение задачи: перемешивание строк в текстовом файле размером 500 - 700 мегабайт. Судя по тому, что у тебя в нескольких темах фигурирует размер файла (именно) до 700 Мб и платформа Delphi\RAD XE4, то это похоже на "вопрос на засыпку". Дело в том, что если текстовый файл представлен в кодировке ANSI (что скорее всего), то на старом\добром Delphi 7 загрузка 700 Мб в TStringList не должна представлять особых проблем. А в версиях Delphi\RAD, использующих по умолчанию юникод, скорее всего будут проблемы в 32-битных приложениях, т.к. при преобразовании ANSI в юникод объем занимаемой памяти (тупо\бестолково) возрастает в два раза. Поэтому, если речь идет о размерах файла до 500-700 Мб (а не о "страшных" гигабайтах, которые явно невозможно загрузить в память в 32-битных приложениях), то решением "проблемы" может быть загрузка строк не в стандартный TStringList, хранящий string в формате юникод, а в некий TList (обычный или дженерик), хранящий AnsiString. |
Сообщ.
#12
,
|
|
|
И всё же, leo, наибольший интерес представляет именно сортировка текстового файла с количеством строк в миллионы..миллиарды. Именно такое красивое решение я бы, как преподаватель, оценил=похвалил. А пока никто такового не предложил.
|
Сообщ.
#13
,
|
|
|
Цитата Славян @ наибольший интерес представляет именно сортировка текстового файла с количеством строк в миллионы..миллиарды. А я считаю, что текстовые файлы размером даже в сотни Мб - это уже нонсенс и верх тупости\идиотизма. А заниматься тупой "сортировкой" таких файлов (без преобразования формата, создания вспомогательных индексных файлов и т.п.) - это еще большая тупость\идиотизм |
Сообщ.
#14
,
|
|
|
leo, кабы сортировка! У ТС надо просто перемешать. А на... э-э-э, зачем???
|
Сообщ.
#15
,
|
|
|
LMM
Так в задании сказано что нельзя копироввть в память |