Правка. Разбитие текста (Delphi).

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by Alina2015, 4 Feb 2018.

  1. Alina2015

    Alina2015 New Member

    Joined:
    29 Jan 2018
    Messages:
    11
    Likes Received:
    2
    Reputations:
    0
    Этот код делит файл на части.

    И вот вопрос: Есть один минус и сразу вопрос: Как сделать что бы если количество строк не кратно количеству частей то последний файл меньше ?. То есть пусть все первые файлы равны, последний меньше.

    Потому что в данном случае делит не правильно.


    Code:
    procedure TForm1.Button1Click(Sender: TObject);
    const
      //Количество частей на которые надо разбить файл.
      N = 10;
    var
      F1, F2 : File;
      i, SizePart, SizePartAdd : Cardinal;
      Buff : array of Byte;
    begin
      if OpenDialog1.InitialDir = '' then begin
        OpenDialog1.InitialDir := ExtractFilePath(Application.ExeName);
      end;
      if not OpenDialog1.Execute then Exit;
      if not FileExists(OpenDialog1.FileName) then begin
        ShowMessage('Указанный файл не найден. Действие отменено.');
        Exit;
      end;
     
      AssignFile(F1, OpenDialog1.FileName);
      Reset(F1, 1);
     
      if FileSize(F1) < N then begin
        ShowMessage('Указанный файл слишком мал. Разбиение отменено.');
        CloseFile(F1);
        Exit;
      end;
     
      SizePart := FileSize(F1) div N;
      SizePartAdd := FileSize(F1) mod N;
     
      SetLength(Buff, SizePart);
     
      for i := 1 to N do begin
        AssignFile(F2, OpenDialog1.FileName + '.part' + IntToStr(i));
        Rewrite(F2, 1);
        BlockRead(F1, Pointer(Buff)^, SizePart);
        BlockWrite(F2, Pointer(Buff)^, SizePart);
        if (i = N) and (SizePartAdd > 0) then begin
          BlockRead(F1, Pointer(Buff)^, SizePartAdd);
          BlockWrite(F2, Pointer(Buff)^, SizePartAdd);
        end;
        CloseFile(F2);
      end;
     
      CloseFile(F1);
    end;
     
  2. #colorblind

    #colorblind Moderator

    Joined:
    31 Jan 2014
    Messages:
    637
    Likes Received:
    246
    Reputations:
    42
    Перечитывал раз 5, но так и не понял вопроса
     
    Alina2015 likes this.
  3. Alina2015

    Alina2015 New Member

    Joined:
    29 Jan 2018
    Messages:
    11
    Likes Received:
    2
    Reputations:
    0
    Нужно в этом коде исправить чтобы файл разбивался как построчно, так и по файлам. Две функции.
    Есть вот такой код но он медленный. Тот что выше работает с большими размерами файлов. А этот нет и постоянно ошибка -out-of-memory-delphi (В этом что ниже).
    Code:
    procedure TForm1.Button1Click(Sender: TObject);
    var n,k,i,j,p,q:integer;
        t,t1:TStringList;
    begin
    n:=strtoint(Edit1.Text);//количество разбиений
    t:=TStringList.Create;
    t.LoadFromFile('0.txt');
    //если число строк кратно n
    if t.Count mod n=0 then k:=t.Count div n
    else k:=t.Count div n+1;//если не кратно, то последний файл меньше
    i:=0;
    p:=0; //номер файла
    while i<t.Count do
     begin
      t1:=TStringList.Create;
      inc(p);
      if t.Count-i-1<k then q:=t.Count-1 //если осталось меньше k строк
      else q:=i+k-1;
      for j:=i to q do
      t1.Add(t[j]);
      t1.SaveToFile(inttostr(p)+'.txt');
      t1.Free;
      i:=i+k;
     end;
    t.Free;
    end;
     
  4. #colorblind

    #colorblind Moderator

    Joined:
    31 Jan 2014
    Messages:
    637
    Likes Received:
    246
    Reputations:
    42
    Как я уже говорил в предыдущей теме, StringList это зло. Удобно конечно, но не знаешь как оно будет работать при больших объемах
    Code:
    program Project1;
    {$WARNINGS OFF}
    {$HINTS OFF}
    {$APPTYPE CONSOLE}
    
    uses
      SysUtils, windows, math;
    
    var
      fHandle: DWORD;
      fSize:DWORD;
                                                                                        //хэндл файла, который делим
      BytesRead: DWORD;                                                                 //кол-во записаных/считаных байт
    
      pBuf: Pointer;                                                                    //буфер для чтения/записи частей
      partSize: integer;                                                                //размер равных частей
    
      SpecificLast:byte;                                                                //триггер неравной последней части
      lastPartSize: integer;                                                            //размер последней части
      i:integer;
    
      nfHandle: DWORD;                                                                  //хэндл создаваемой части
    const
      partCount = 9;                                                                    //количество частей
    
    begin                                                                               //Открываем файл
    fHandle:= CreateFileA('./Base2.txt', GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    
    fSize:=GetFileSize(fHandle, nil)                                               //Получаем размер файла в байтах
    
    if fSize mod partCount <> 0                                                         //Проверяем делится ли нацело
    then begin
          SpecificLast:=1;                                                              //Если нет, тогда делаем дописывание неравной части
          partSize:=Round(RoundTo(fSize/partCount, -2));                                //Размер частей вычисляется через округление
          lastPartSize:=fSize-partSize*(partCount-1);                                   //Размер последней части=размер файла - количество частей * размер растей
         end
    else partSize:=fSize div partCount;                                                 //Делим нацело
    
    Writeln('File size: ', fSize);
    Writeln('Part count: ', partCount);
    Writeln('Part size: ', partSize);
    Writeln('LastPart size: ', lastPartSize);
    
    pBuf:=VirtualAlloc(nil, partSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);       //Выделяем память под буфер
    
    for i:=1 to partCount-SpecificLast do                                               //Кол-во итерраций в зависимости от деления нацело
      begin
        nfHandle:= CreateFileA(PChar('Part'+IntToStr(i)+'.txt'), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
        ReadFile(fHandle, pBuf^, partSize, BytesRead, nil);                             //Читаем из файла в буфер
        WriteFile(nfHandle, pBuf^, partSize, BytesRead, nil);                           //Пишем из буфера в файл
        CloseHandle(nfHandle);                                                          //Закрываем хэндл текущей части
      end;
    
    VirtualFree(pBuf, 0, MEM_RELEASE);                                                  //Освобождаем буфер
    
    if SpecificLast=1
    then begin
          pBuf:=VirtualAlloc(nil, lastPartSize, MEM_COMMIT or MEM_RESERVE, PAGE_READWRITE);       //Выделяем память под буфер для остатков
          nfHandle:= CreateFileA(PChar('Part'+IntToStr(partCount)+'.txt'), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
          ReadFile(fHandle, pBuf^, lastPartSize, BytesRead, nil);                                 //И делаем все то же
          WriteFile(nfHandle, pBuf^, lastPartSize, BytesRead, nil);                               //что и в цикле выше
          CloseHandle(nfHandle);                                                                  //только с меньшим размером
          VirtualFree(pBuf, 0, MEM_RELEASE);
         end;
    
    Writeln('Done!');
    Readln;
    
    CloseHandle(fHandle);                                                               //Закрываем открытый файл со строками
    end.
    
    Как-то так. по-идее проблем с памятью быть не должно. Хотя если ты хочешь обрабатывать многогигобайтные файлы на компе со 128МБ оперативы, то код конечно придется переписывать

    p.s.: еще нужно дописать проверку возвращаемых значений, посколько это пример, я защиту от дурака не писал)
     
    Alina2015 likes this.
  5. Alina2015

    Alina2015 New Member

    Joined:
    29 Jan 2018
    Messages:
    11
    Likes Received:
    2
    Reputations:
    0
    А как дописать проверку возвращаемых значений ?
     
  6. #colorblind

    #colorblind Moderator

    Joined:
    31 Jan 2014
    Messages:
    637
    Likes Received:
    246
    Reputations:
    42
    Ну например здесь:
    Code:
    fHandle:= CreateFileA('./Base2.txt', GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    fHandle не должен быть равен INVALID_HANDLE_VALUE. Подробнее про функцию CreateFileA можно почитать тут: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx или тут http://vsokovikov.narod.ru/New_MSDN_API/Menage_files/fn_createfile.htm

    По аналогии и с остальными вызовами WinAPI
     
    Alina2015 likes this.