На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
  
> Разбить файл на указанное количество строк \ Доработка
    Ребята, выручите в решении данного вопроса.
    Задание: Есть текстовый файл, в котором 150000 строк. Указываю число 15000 (на сколько строк разбить) и программа разбивает его на файлы, в каждом из которых 15000 строк. Получаю результат в виде 10 файлов по 15000 строк в каждом. Если остается остаток меньше 15000 строк, то его записываем в последний файл.

    Код что ниже - работает. Но меня смущает вот этот участок кода (Тут остаточная часть, текстового файла - грузится в память и жестко -забивает её. Как можно переделать построчно ?):
    ExpandedWrap disabled
      // Если осталось прочитано строк меньше, чем значение 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;



    Вот основной код в котором есть участок кода что выше:
    ExpandedWrap disabled
      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;
      Я б построчно делал, всё равно всё прокэшируется и существенного отличия не увижу:
      ExpandedWrap disabled
        for i:=0 to N-1 do
        begin
          if (i mod K)=0 then поменятьФайлВыхода; // сравнение на каждой строке ничтожно по времени в сравнении с чтением строки (ниже)
          ReadLn( входной ... )
          WriteLn( выходной ...);
          Inc(i);
        end;


      Добавлено
      Inc, небось, не нужен, сие на автомате в Паскале (не помню). :blush:
        Славян, Идея, но к примеру если делить по 11 000 000 строк то даже в построчном чтении выскакивает ошибка нехватки памяти... Почему так ?
          Не, ничего не выскакивает! :no: Надо просто эту же строку и записывать, а не класть в список, кой потом хочется махом сбросить в файл. Сразу делайте (запись прочитаной строчки) и всё будет норм. :yes:
            Славян, Ух и ох :), помогите исправить. Чего то я сегодня вообще туплю и конкретно.
              Цитата Kirilis2018 @
              если делить по 11 000 000 строк то даже в построчном чтении выскакивает ошибка нехватки памяти...
              Именно такое быть может, думается, токмо если в файле всего несколько строк (а задали "делить по 11 млн"), но каждая строка - в несколько гигабайт. :jokingly: Ну тогда - да, надо будет тщательнее строку порциями читать/записывать. Но тут явно не этот (весьма экзотический) случай.

              Добавлено
              Цитата Kirilis2018 @
              помогите исправить.
              Да легко. Бросьте код с построчным чтением/записью, - посмотрим что и как там осталось дошлифовать.
                Славян, тут файл в 1 гигабайт и его нужно разделить на 11 000 000 строк. Строки не длинные, по 120 символов строка. И остаток, если меньше 11 000 000 записать в отдельный файл. Вот потому не знаю как правильно оптимизировать код и прошу потому помощи!

                Добавлено
                Славян, Вот мой код, посмотрите:
                ExpandedWrap disabled
                  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;
                Сообщение отредактировано: Kirilis2018 -
                  Так всё ж написано же! Ваяйте нечто вида:
                  ExpandedWrap disabled
                          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); // Закрываем хвост
                    Славян, Туплю немного я еще, ну попробую разобраться. И на этом спасибо.
                      В итоге так заработало:
                      ExpandedWrap disabled
                            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); // Закрываем хвост
                      Имена входных/выходных файлов поправьте на свои.
                        Славян, 1000 благодарностей и миллионы плюсов - Вам!. Все заработало как нужно!. Я 4 часа долбил код, по своей неопытности. А у Вас мгновенно все получилось. Низкий поклон Вам! :good:
                        Сообщение отредактировано: Kirilis2018 -
                          Эх, хорошо, если бы вы проверили 2 способа: построчный и через списки строк, да сказали нам отличия по времени. А то у меня вроде нет таких могучих текстовых файлов. Хотя... есть один XML на 15 гиг, но... как-то неохота возиться, если честно. :'(
                            Славян, Проверил, на файле в 8 гигабайт. Построчно, у меня, обрабатывает за 30 минут 41 секунду , и через списки строк за 24 минуты 25 секунд. Но построчно тянет большие куски а вот в варианте по списку, крошиться оперативная память, даже на 500 мегабайтах. Потому, преимущественно - использовать вариант построчно, как для меня. У кого, правда, оперативы туча, то можно и по списку - но по скорости, этот вариант, особо не выигрывает. Это конечно мое мнение, я не сильно опытный в программировании, можно сказать начинающий.
                            Сообщение отредактировано: Kirilis2018 -
                              Цитата Kirilis2018 @
                              построчно тянет большие куски а вот в варианте по списку, крошиться оперативная память, даже на 500 мегабайтах.
                              Ясно. Спасибо!! Надо будет самому́ что-то в этом варианте покопать - интересно стало! :thanks:
                                Славян, Да это Вам спасибо. Я просто разными документами занимаюсь. И мне вот программы по тексту нужны. Но то что продают просто жесть... Потому пытаюсь сам под свои нужды сделать. Еще раз спасибо!
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0544 ]   [ 17 queries used ]   [ Generated: 19.04.24, 09:21 GMT ]