[Delphi] Побитовые чтение и запись файл-массив-файл

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by immortalist, 1 Feb 2011.

  1. immortalist

    immortalist Member

    Joined:
    16 Jan 2010
    Messages:
    99
    Likes Received:
    64
    Reputations:
    37
    Доброго времени суток, античат!
    Делаю блекслист в софте как массив бит:
    Code:
    globalblack:array[0..16000000]of Byte;
    Все работает отлично, поиск просто шикарен, но вот небольшой минус: если представлять этот массив в файле как просто последовательность 0/1 - выходит 128 метров, и грузит/сохраняет долго =\
    Подскажите, как можно побитово прочитать файл и загнать его значения в массив, и как потом этот массив записать обратно в файл. Экономия в 8 раз получится =\ Всем заранее спасибо =*
     
  2. alexey-m

    alexey-m Elder - Старейшина

    Joined:
    15 Jul 2009
    Messages:
    518
    Likes Received:
    100
    Reputations:
    37
    если все правильно понял, то как вариант могу предложить такое решение:
    Code:
    type
      TAByte = array of Byte;
    
    procedure BitFile(Pfile: String; var AByte: TAByte);
    var
      hFileMap, hFile: THandle;
      lpMem: Pointer;
      FileSize, i: DWORD;
      b: Byte;
    begin
      hFile:= CreateFile(PChar(Pfile),
                         GENERIC_READ,
                         FILE_SHARE_READ or FILE_SHARE_WRITE,
                         nil,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN,
                         0);
    
      if hFile <> INVALID_HANDLE_VALUE then begin
        FileSize:= GetFileSize(hFile, nil);
        hFileMap:= CreateFileMappingA(hFile, nil, PAGE_READONLY, 0, FileSize, nil);
    
        if hFileMap <> INVALID_HANDLE_VALUE then begin
    
          CloseHandle(hFile);
          lpMem:= MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, FileSize);
          if lpMem <> nil then begin
            SetLength(AByte,FileSize*8);
            for i:= 0 to FileSize - 1 do begin
              b:= PByte(DWORD(lpMem) + i)^;
              AByte[8*i*]:= b and 1;
              AByte[8*i+1]:= b shr 1 and 1;
              AByte[8*i+2]:= b shr 2 and 1;
              AByte[8*i+3]:= b shr 3 and 1;
              AByte[8*i+4]:= b shr 4 and 1;
              AByte[8*i+5]:= b shr 5 and 1;
              AByte[8*i+6]:= b shr 6 and 1;
              AByte[8*i+7]:= b shr 7 and 1;
            end;
            UnmapViewOfFile(lpMem);
          end;
          CloseHandle(hFileMap);
        end;
      end;
    end;
    
    соответственно запись в файл:
    Code:
    procedure WriteBitFile(Pfile: String; const AByte: TAByte);
    var
      hFileMap, hFile: THandle;
      lpMem: Pointer;
      dwSize, i: DWORD;
      b: Byte;
    begin
      hFile:= CreateFile(PChar(Pfile),
                         GENERIC_READ or GENERIC_WRITE,
                         FILE_SHARE_READ or FILE_SHARE_WRITE,
                         nil,
                         CREATE_ALWAYS,
                         FILE_ATTRIBUTE_NORMAL,
                         0);
    
      if hFile <> INVALID_HANDLE_VALUE then begin
        dwSize:= (High(AByte) + 1) div 8;
        hFileMap:= CreateFileMappingA(hFile, nil, PAGE_READWRITE, 0, dwSize, nil);
    
        if hFileMap <> INVALID_HANDLE_VALUE then begin
    
          CloseHandle(hFile);
          lpMem:= MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, dwSize);
          if lpMem <> nil then begin
    
    
            for i:= 0 to dwSize - 1 do begin
    
              b:= AByte[8*i+0] or
                  AByte[8*i+1] shl 1 or
                  AByte[8*i+2] shl 2 or
                  AByte[8*i+3] shl 3 or
                  AByte[8*i+4] shl 4 or
                  AByte[8*i+5] shl 5 or
                  AByte[8*i+6] shl 6 or
                  AByte[8*i+7] shl 7;
    
              PByte(DWORD(lpMem) + i)^:= b;
            end;
            UnmapViewOfFile(lpMem);
          end;
          CloseHandle(hFileMap);
        end;
      end;
    end;
    
    ну и как пример для наглядности, в мемо1 будет последовательность бит
    Code:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      i: Word;
      AByte: TAByte;
    begin
      Memo1.Clear;
    
      BitFile('c:\test.txt', AByte);
    
      for i:= 0 to High(AByte) do
        Memo1.Lines.Add(IntToStr(AByte[i]));
     ................
      WriteBitFile('c:\test2.txt',AByte);
    
    end;
    
     
    #2 alexey-m, 1 Feb 2011
    Last edited: 1 Feb 2011
  3. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Реально проще тогда файл маппинг + спец функция чтения и установки бита.
    Типа
    mem : pchar;
    mem := место куда отобразили файл.


    чтобы считать определенный бит (index допустим задает порядковый номер), то
    c := mem[index div 8];
    result := (c and Pow2(index%8) <> 0);

    где Pow - функция возвращает число = степень двойки
    таким обработм result будет true если установлен бит и false если сброшен.

    Для записи бита делаем подобное тоже. Типа
    c := mem[index div 8];

    с := с or Pow2(index%8);
    mem[index div 8] = c;

    Ну там еще приведенение типов итд итп. Так будет самый быстрый вариант.