Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.15.235.196] |
|
Сообщ.
#1
,
|
|
|
Ребята, выручите в решении данного вопроса.
Задание: Есть текстовый файл, в котором 150000 строк. Указываю число 15000 (на сколько строк разбить) и программа разбивает его на файлы, в каждом из которых 15000 строк. Получаю результат в виде 10 файлов по 15000 строк в каждом. Если остается остаток меньше 15000 строк, то его записываем в последний файл. Код что ниже - работает. Но меня смущает вот этот участок кода (Тут остаточная часть, текстового файла - грузится в память и жестко -забивает её. Как можно переделать построчно ?): // Если осталось прочитано строк меньше, чем значение Amount, то // эти строки будут содержаться в OutputFile. Все, что останется - загрузить // предыдущий файл и добавить к нему эти строки. В связи с этим приходиться // создавать дополнительный список. TempList := TStringList.Create; try TempList.LoadFromFile(OutputFileName + IntToStr(Index - 1) + FileExt); TempList.AddStrings(OutputFile); TempList.SaveToFile(OutputFileName + IntToStr(Index - 1) + FileExt); finally TempList.Free; Вот основной код в котором есть участок кода что выше: procedure TForm1.aButton1Click(Sender: TObject); var FileToRead: TextFile; TempList: TStringList; OutputFile: TStringList; ReadString: String; OutputFileName: String; FileExt: String; Amount: Integer; CurrentStringIndex: Integer; LineIndex: Integer; Index: Integer; Delta: Integer; i: Integer; begin Amount := 6; OutputFileName := 'C:\FileName_'; FileExt := '.txt'; // Открываем файл для чтения AssignFile(FileToRead, 'C:\FileToRead.txt'); try Reset(FileToRead); OutputFile := TStringlist.Create; try CurrentStringIndex := 0; LineIndex := 0; Index := 0; // Работаем со строками в файле, открытом для чтения while not EoF(FileToRead) do begin if LineIndex <> Amount then begin // Читаем строку из файла ReadLn(FileToRead, ReadString); // Добавляем строку в список OutputFile.Add(ReadString); Inc(CurrentStringIndex); Inc(LineIndex); end else // Прочитали нужное количество строк - сохраним их! begin LineIndex := 0; OutputFile.SaveToFile(OutputFileName + IntToStr(Index) + FileExt); OutputFile.Clear; // Увеличиваем индекс файла Inc(Index); end; end; // Если осталось прочитано строк меньше, чем значение Amount, то // эти строки будут содержаться в OutputFile. Все, что останется - загрузить // предыдущий файл и добавить к нему эти строки. В связи с этим прходится // создавать дополнительный список. TempList := TStringList.Create; try TempList.LoadFromFile(OutputFileName + IntToStr(Index - 1) + FileExt); TempList.AddStrings(OutputFile); TempList.SaveToFile(OutputFileName + IntToStr(Index - 1) + FileExt); finally TempList.Free; end; finally OutputFile.Free; end; finally // Закрываем файл CloseFile(FileToRead); end; end; |
Сообщ.
#2
,
|
|
|
Я б построчно делал, всё равно всё прокэшируется и существенного отличия не увижу:
for i:=0 to N-1 do begin if (i mod K)=0 then поменятьФайлВыхода; // сравнение на каждой строке ничтожно по времени в сравнении с чтением строки (ниже) ReadLn( входной ... ) WriteLn( выходной ...); Inc(i); end; Добавлено Inc, небось, не нужен, сие на автомате в Паскале (не помню). |
Сообщ.
#3
,
|
|
|
Славян, Идея, но к примеру если делить по 11 000 000 строк то даже в построчном чтении выскакивает ошибка нехватки памяти... Почему так ?
|
Сообщ.
#4
,
|
|
|
Не, ничего не выскакивает! Надо просто эту же строку и записывать, а не класть в список, кой потом хочется махом сбросить в файл. Сразу делайте (запись прочитаной строчки) и всё будет норм.
|
Сообщ.
#5
,
|
|
|
Славян, Ух и ох , помогите исправить. Чего то я сегодня вообще туплю и конкретно.
|
Сообщ.
#6
,
|
|
|
Цитата Kirilis2018 @ Именно такое быть может, думается, токмо если в файле всего несколько строк (а задали "делить по 11 млн"), но каждая строка - в несколько гигабайт. Ну тогда - да, надо будет тщательнее строку порциями читать/записывать. Но тут явно не этот (весьма экзотический) случай. если делить по 11 000 000 строк то даже в построчном чтении выскакивает ошибка нехватки памяти... Добавлено Цитата Kirilis2018 @ Да легко. Бросьте код с построчным чтением/записью, - посмотрим что и как там осталось дошлифовать. помогите исправить. |
Сообщ.
#7
,
|
|
|
Славян, тут файл в 1 гигабайт и его нужно разделить на 11 000 000 строк. Строки не длинные, по 120 символов строка. И остаток, если меньше 11 000 000 записать в отдельный файл. Вот потому не знаю как правильно оптимизировать код и прошу потому помощи!
Добавлено Славян, Вот мой код, посмотрите: procedure Tfrm_Main.Button1Click(Sender: TObject); var FileToRead: TextFile; TempList: TStringList; OutputFile: TStringList; ReadString: String; OutputFileName: String; FileExt,_FilePath: String; Amount: Integer; CurrentStringIndex: Integer; LineIndex: Integer; p: Integer; Index: Integer; Delta: Integer; i: Integer; begin if opendialog6.execute then Amount := 11000000; OutputFileName := 'File'; FileExt := '.txt'; // Открываем файл для чтения AssignFile(FileToRead, opendialog6.filename); try Reset(FileToRead); OutputFile := TStringlist.Create; try CurrentStringIndex := 0; LineIndex := 0; Index := 1; // Работаем со строками в файле, открытом для чтения while not EoF(FileToRead) do begin if LineIndex <> Amount then begin // Читаем строку из файла ReadLn(FileToRead, ReadString); // Добавляем строку в список OutputFile.Add(ReadString); Inc(CurrentStringIndex); Inc(LineIndex); end else // Прочитали нужное количество строк - сохраним их! begin LineIndex := 0; CreateDir('f' + inttostr(Index)); OutputFile.SaveToFile('f' + inttostr(Index)+'\' + OutputFileName + IntToStr(Index)+ FileExt); OutputFile.Clear; // Увеличиваем индекс файла Inc(Index); end; end; // Сохраняем остаток TempList := TStringList.Create; try TempList.AddStrings(OutputFile); TempList.SaveToFile('f' +IntToStr(Index) + FileExt); finally TempList.Free; end; finally OutputFile.Free; end; finally // Закрываем файл CloseFile(FileToRead); end; end; |
Сообщ.
#8
,
|
|
|
Так всё ж написано же! Ваяйте нечто вида:
LineIndex := 0; // Работаем со строками в файле, открытом для чтения while not EoF(FileToRead) do begin if LineIndex mod Amount = 0 then begin CloseFile(FileToWrite); // Закрываем предыдущий файл ReadString := OutputFileName + IntToStr(Index) + FileExt // выходной (тут бы ведущие нули) AssignFile(FileToWrite, ReadString); // как-то для записи. Не помню как в Паскале end; ReadLn(FileToRead, ReadString); // Читаем строку из файла WriteLn(FileToWrite, ReadString); // Пишем строку в файл Inc(LineIndex); // ещё одну строку обработали! end; ... CloseFile(FileToWrite); // Закрываем хвост |
Сообщ.
#9
,
|
|
|
Славян, Туплю немного я еще, ну попробую разобраться. И на этом спасибо.
|
Сообщ.
#10
,
|
|
|
В итоге так заработало:
FileName := 'D:\1\22'; Amount := 4; Index := 0; LineIndex := 0; // Работаем со строками в файле, открытом для чтения // Открываем файл для чтения AssignFile(FileToRead, FileName); Reset( FileToRead ); OutputFileName := 'd:\1\File'; FileExt := '.txt'; ReadString := OutputFileName + IntToStr(Index) + FileExt; // выходной (тут бы ведущие нули) AssignFile( FileToWrite, ReadString); // как-то для записи. Не помню как в Паскале ReWrite( FileToWrite ); while not EoF(FileToRead) do begin if (LineIndex mod Amount) = 0 then begin CloseFile(FileToWrite); // Закрываем предыдущий файл ReadString := OutputFileName + IntToStr(Index) + FileExt; // выходной (тут бы ведущие нули) AssignFile(FileToWrite, ReadString); // как-то для записи. Не помню как в Паскале ReWrite( FileToWrite ); // вот как в Паскале Inc(Index) // ещё один файл начали! end; ReadLn(FileToRead, ReadString); // Читаем строку из файла WriteLn(FileToWrite, ReadString); // Пишем строку в файл Inc(LineIndex) // ещё одну строку обработали! end; // ... CloseFile(FileToRead); // Закрываем CloseFile(FileToWrite); // Закрываем хвост |
Сообщ.
#11
,
|
|
|
Славян, 1000 благодарностей и миллионы плюсов - Вам!. Все заработало как нужно!. Я 4 часа долбил код, по своей неопытности. А у Вас мгновенно все получилось. Низкий поклон Вам!
|
Сообщ.
#12
,
|
|
|
Эх, хорошо, если бы вы проверили 2 способа: построчный и через списки строк, да сказали нам отличия по времени. А то у меня вроде нет таких могучих текстовых файлов. Хотя... есть один XML на 15 гиг, но... как-то неохота возиться, если честно.
|
Сообщ.
#13
,
|
|
|
Славян, Проверил, на файле в 8 гигабайт. Построчно, у меня, обрабатывает за 30 минут 41 секунду , и через списки строк за 24 минуты 25 секунд. Но построчно тянет большие куски а вот в варианте по списку, крошиться оперативная память, даже на 500 мегабайтах. Потому, преимущественно - использовать вариант построчно, как для меня. У кого, правда, оперативы туча, то можно и по списку - но по скорости, этот вариант, особо не выигрывает. Это конечно мое мнение, я не сильно опытный в программировании, можно сказать начинающий.
|
Сообщ.
#14
,
|
|
|
Цитата Kirilis2018 @ Ясно. Спасибо!! Надо будет самому́ что-то в этом варианте покопать - интересно стало! построчно тянет большие куски а вот в варианте по списку, крошиться оперативная память, даже на 500 мегабайтах. |
Сообщ.
#15
,
|
|
|
Славян, Да это Вам спасибо. Я просто разными документами занимаюсь. И мне вот программы по тексту нужны. Но то что продают просто жесть... Потому пытаюсь сам под свои нужды сделать. Еще раз спасибо!
|