Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.02.2018, 14:47   #1
darkwellroad
Пользователь
 
Регистрация: 01.09.2013
Сообщений: 83
По умолчанию Построчное чтение

Привет всем. Нужно сверять между собой два больших файла и удалить из первого те строки, которые есть в обоих файлах. Есть уже рабочий вариант, но в целях обучения хочу сделать это через mmf. Пока-что пытаюсь разобраться как просто построчно читать из файла:
Код:
procedure TForm1.Button2Click(Sender: TObject);
var
  file_, map: dword;
  buf: pointer;
begin
  file_ := CreateFile('D:\10.txt', GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
  if file_ <> INVALID_HANDLE_VALUE then
    try
      map := CreateFileMapping(file_, nil, PAGE_READONLY, 0, 0, nil);
      if map <> 0 then
        try
          buf := MapViewOfFile(map, FILE_MAP_READ, 0, 0, 0);
          if buf <> nil then
            try

            finally
              UnmapViewOfFile(buf)
            end
        finally
          CloseHandle(map)
        end
    finally
      CloseHandle(file_)
    end
Подскажите, как дальше работать с файлом и достичь нужного результата? Заранее благодарю

Последний раз редактировалось darkwellroad; 28.02.2018 в 14:53.
darkwellroad вне форума Ответить с цитированием
Старый 28.02.2018, 15:05   #2
min@y™
Цифровой кот
Старожил
 
Аватар для min@y™
 
Регистрация: 29.08.2014
Сообщений: 7,656
По умолчанию

Смотри сюды, какая красота:
Код:
unit MappedFileStream;

interface

uses
  Windows,
  SysUtils,
  Classes;

type
  TMappedFileStream = class(TStream)
  private
    hMapping : THandle;   // Handle de l'objet file-mapping
    FMemory  : pByteArray;// Adresse de base du mapping
    FHandle  : THandle;   // Handle du fichier ouvert pour le mapping
    FPosition,
    FSize    : Integer;
  public
    // Enregistre les pages modifiées dans le fichier sur le disque
    procedure Flush;
    function  Read(var Buffer; Count: Longint): Longint; override;
    function  Write(const Buffer; Count: Longint): Longint; override;
    function  Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
    property  Memory: pByteArray read FMemory;
    property  Position: Integer read FPosition;
    property  Size : Integer read FSize;
    property  Handle: THandle read FHandle;
    constructor Create(FileName: string;
                       Mode: Word = fmOpenRead;
                       Rights: Cardinal = fmShareExclusive;
                       Offset: Cardinal = 0;
                       MaxSize: Cardinal = 0);
    destructor Destroy; override;
  published
    { Published declarations }
  end;

implementation

procedure TMappedFileStream.Flush;
begin
  FlushViewOfFile(FMemory, 0);
end;

function TMappedFileStream.Read(var Buffer; Count: Integer): Integer;
begin
  if FPosition + Count > Size then Count := Size - FPosition;
  move(FMemory[FPosition], Buffer, Count);
  Result := Count;
end;

function TMappedFileStream.Write(const Buffer; Count: Longint): Longint;
begin
  if FPosition + Count > Size then Count := Size - FPosition;
  move(Buffer, FMemory[FPosition], Count);
  Result := Count;
end;

function TMappedFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
  Case Origin of
  soBeginning:  // Seek from the beginning of the resource. The seek operation moves to a specified position (offset), which must be greater than or equal to zero.
    if Offset < FSize then FPosition := Offset else raise ERangeError.Create('');
  soCurrent  :  // Seek from the current position in the resource. The seek operation moves to an offset from the current position (position + offset). The offset is positive to move forward, negative to move backward.
    if FPosition + Offset < FSize then FPosition := FPosition + Offset else raise ERangeError.Create('');
  soEnd      :  // Seek from the end of the resource. The seek operation moves to an offset from the end of the resource, where the offset is expressed as a negative value because it is moving toward the beginning of the resource.
    if FSize - Offset >= 0 then FPosition := FSize - Offset else raise ERangeError.Create('');
  end;

  result := FPosition;
end;

constructor TMappedFileStream.Create(FileName: string;
                                     Mode: Word = fmOpenRead;
                                     Rights: Cardinal = fmShareExclusive;
                                     Offset: Cardinal = 0;
                                     MaxSize: Cardinal = 0);
var
    dwDA, dwSM, dwCD, flP, dwVA: DWORD;
    FileInfo: _BY_HANDLE_FILE_INFORMATION;
begin
// Initialise correctement les attributs de construction du mapping
  case Mode of
    fmCreate:
      begin
        dwCD := CREATE_ALWAYS;
        dwDA := GENERIC_WRITE and GENERIC_READ;
        dwVA := FILE_MAP_WRITE;
        flP  := PAGE_READWRITE;
      end;
    fmOpenRead:
      begin
        dwCD := OPEN_EXISTING;
        dwDA := GENERIC_READ;
        dwVA := FILE_MAP_READ;
        flP  := PAGE_READONLY;
      end;
    fmOpenWrite:
      begin
        dwCD := TRUNCATE_EXISTING;
        dwDA := GENERIC_WRITE and GENERIC_READ;
        dwVA := FILE_MAP_WRITE;
        flP  := PAGE_READWRITE;
      end;
    fmOpenReadWrite:
      begin
        dwCD := OPEN_EXISTING;
        dwDA := GENERIC_WRITE and GENERIC_READ;
        dwVA := FILE_MAP_WRITE;
        flP  := PAGE_READWRITE;
      end;
  end;

  case Rights of
    fmShareCompat or fmShareExclusive:
      begin
        dwSM := 0;
      end;
    fmShareDenyWrite:
      begin
        dwSM := FILE_SHARE_READ;
      end;
    fmShareDenyRead:
      begin
        dwSM := FILE_SHARE_WRITE;
      end;
    fmShareDenyNone:
      begin
        dwSM := FILE_SHARE_READ and FILE_SHARE_WRITE;
      end;
  end;

// Ouvre le fichier
  FileName := FileName + #0; // Ajout du zero terminal
  FHandle := CreateFile(@FileName[1], dwDA, dwSM, nil, dwCD, 0, 0);
  inherited create;
  if FHandle = INVALID_HANDLE_VALUE then raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));

  if MaxSize = 0 then begin
    if not GetFileInformationByHandle(FHandle, FileInfo) then begin
       CloseHandle(FHandle);
       raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));
    end;
    FSize := FileInfo.nFileSizeLow;
  end else FSize := MaxSize;

  hMapping := CreateFileMapping(FHandle, nil, flP, 0, FSize, nil);
  if hMapping = INVALID_HANDLE_VALUE then begin
    FileClose(FHandle);
    raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));
  end;

  FMemory := MapViewOfFile(hMapping, dwVA, 0, 0, FSize);
  if FMemory = nil then begin
    FileClose(FHandle);
    CloseHandle(hMapping);
    raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));
  end;

end;

destructor TMappedFileStream.Destroy;
begin
  Flush;
  UnMapViewOfFile(FMemory);
  CloseHandle(hMapping);
  CloseHandle(FHandle);
  inherited destroy;
end;

end.
Расскажу я вам, дружочки, как выращивать грибочки: нужно в поле утром рано сдвинуть два куска урана...
min@y™ вне форума Ответить с цитированием
Старый 28.02.2018, 15:12   #3
darkwellroad
Пользователь
 
Регистрация: 01.09.2013
Сообщений: 83
По умолчанию

Цитата:
Сообщение от min@y™ Посмотреть сообщение
Смотри сюды, какая красота:
Код:
unit MappedFileStream;

interface

uses
  Windows,
  SysUtils,
  Classes;

type
  TMappedFileStream = class(TStream)
  private
    hMapping : THandle;   // Handle de l'objet file-mapping
    FMemory  : pByteArray;// Adresse de base du mapping
    FHandle  : THandle;   // Handle du fichier ouvert pour le mapping
    FPosition,
    FSize    : Integer;
  public
    // Enregistre les pages modifiées dans le fichier sur le disque
    procedure Flush;
    function  Read(var Buffer; Count: Longint): Longint; override;
    function  Write(const Buffer; Count: Longint): Longint; override;
    function  Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override;
    property  Memory: pByteArray read FMemory;
    property  Position: Integer read FPosition;
    property  Size : Integer read FSize;
    property  Handle: THandle read FHandle;
    constructor Create(FileName: string;
                       Mode: Word = fmOpenRead;
                       Rights: Cardinal = fmShareExclusive;
                       Offset: Cardinal = 0;
                       MaxSize: Cardinal = 0);
    destructor Destroy; override;
  published
    { Published declarations }
  end;

implementation

procedure TMappedFileStream.Flush;
begin
  FlushViewOfFile(FMemory, 0);
end;

function TMappedFileStream.Read(var Buffer; Count: Integer): Integer;
begin
  if FPosition + Count > Size then Count := Size - FPosition;
  move(FMemory[FPosition], Buffer, Count);
  Result := Count;
end;

function TMappedFileStream.Write(const Buffer; Count: Longint): Longint;
begin
  if FPosition + Count > Size then Count := Size - FPosition;
  move(Buffer, FMemory[FPosition], Count);
  Result := Count;
end;

function TMappedFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64;
begin
  Case Origin of
  soBeginning:  // Seek from the beginning of the resource. The seek operation moves to a specified position (offset), which must be greater than or equal to zero.
    if Offset < FSize then FPosition := Offset else raise ERangeError.Create('');
  soCurrent  :  // Seek from the current position in the resource. The seek operation moves to an offset from the current position (position + offset). The offset is positive to move forward, negative to move backward.
    if FPosition + Offset < FSize then FPosition := FPosition + Offset else raise ERangeError.Create('');
  soEnd      :  // Seek from the end of the resource. The seek operation moves to an offset from the end of the resource, where the offset is expressed as a negative value because it is moving toward the beginning of the resource.
    if FSize - Offset >= 0 then FPosition := FSize - Offset else raise ERangeError.Create('');
  end;

  result := FPosition;
end;

constructor TMappedFileStream.Create(FileName: string;
                                     Mode: Word = fmOpenRead;
                                     Rights: Cardinal = fmShareExclusive;
                                     Offset: Cardinal = 0;
                                     MaxSize: Cardinal = 0);
var
    dwDA, dwSM, dwCD, flP, dwVA: DWORD;
    FileInfo: _BY_HANDLE_FILE_INFORMATION;
begin
// Initialise correctement les attributs de construction du mapping
  case Mode of
    fmCreate:
      begin
        dwCD := CREATE_ALWAYS;
        dwDA := GENERIC_WRITE and GENERIC_READ;
        dwVA := FILE_MAP_WRITE;
        flP  := PAGE_READWRITE;
      end;
    fmOpenRead:
      begin
        dwCD := OPEN_EXISTING;
        dwDA := GENERIC_READ;
        dwVA := FILE_MAP_READ;
        flP  := PAGE_READONLY;
      end;
    fmOpenWrite:
      begin
        dwCD := TRUNCATE_EXISTING;
        dwDA := GENERIC_WRITE and GENERIC_READ;
        dwVA := FILE_MAP_WRITE;
        flP  := PAGE_READWRITE;
      end;
    fmOpenReadWrite:
      begin
        dwCD := OPEN_EXISTING;
        dwDA := GENERIC_WRITE and GENERIC_READ;
        dwVA := FILE_MAP_WRITE;
        flP  := PAGE_READWRITE;
      end;
  end;

  case Rights of
    fmShareCompat or fmShareExclusive:
      begin
        dwSM := 0;
      end;
    fmShareDenyWrite:
      begin
        dwSM := FILE_SHARE_READ;
      end;
    fmShareDenyRead:
      begin
        dwSM := FILE_SHARE_WRITE;
      end;
    fmShareDenyNone:
      begin
        dwSM := FILE_SHARE_READ and FILE_SHARE_WRITE;
      end;
  end;

// Ouvre le fichier
  FileName := FileName + #0; // Ajout du zero terminal
  FHandle := CreateFile(@FileName[1], dwDA, dwSM, nil, dwCD, 0, 0);
  inherited create;
  if FHandle = INVALID_HANDLE_VALUE then raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));

  if MaxSize = 0 then begin
    if not GetFileInformationByHandle(FHandle, FileInfo) then begin
       CloseHandle(FHandle);
       raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));
    end;
    FSize := FileInfo.nFileSizeLow;
  end else FSize := MaxSize;

  hMapping := CreateFileMapping(FHandle, nil, flP, 0, FSize, nil);
  if hMapping = INVALID_HANDLE_VALUE then begin
    FileClose(FHandle);
    raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));
  end;

  FMemory := MapViewOfFile(hMapping, dwVA, 0, 0, FSize);
  if FMemory = nil then begin
    FileClose(FHandle);
    CloseHandle(hMapping);
    raise Exception.Create('Erreur Windows N°' + IntToStr(GetLastError));
  end;

end;

destructor TMappedFileStream.Destroy;
begin
  Flush;
  UnMapViewOfFile(FMemory);
  CloseHandle(hMapping);
  CloseHandle(FHandle);
  inherited destroy;
end;

end.
Бро ушел тестить
darkwellroad вне форума Ответить с цитированием
Старый 28.02.2018, 21:58   #4
darkwellroad
Пользователь
 
Регистрация: 01.09.2013
Сообщений: 83
По умолчанию

Как можно читать строку, если не посимвольно?
darkwellroad вне форума Ответить с цитированием
Старый 28.02.2018, 22:06   #5
min@y™
Цифровой кот
Старожил
 
Аватар для min@y™
 
Регистрация: 29.08.2014
Сообщений: 7,656
По умолчанию

Цитата:
Сообщение от darkwellroad Посмотреть сообщение
Как можно читать строку, если не посимвольно?
блоками по N кбайт и уже в памяти делить/анализировать.
Ващще, об каких объёмах данных идёт реч? 100+ Гб?
Расскажу я вам, дружочки, как выращивать грибочки: нужно в поле утром рано сдвинуть два куска урана...
min@y™ вне форума Ответить с цитированием
Старый 28.02.2018, 22:13   #6
darkwellroad
Пользователь
 
Регистрация: 01.09.2013
Сообщений: 83
По умолчанию

Цитата:
Сообщение от min@y™ Посмотреть сообщение
блоками по N кбайт и уже в памяти делить/анализировать.
Ващще, об каких объёмах данных идёт реч? 100+ Гб?
Вообщем прикладываю сорец:
Код:
program revice;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  windows,
  SysUtils,
  classes,
  Masks,
  flcDataStructs;

var
  IntroDictionary: TSparseWideStringArray;
  BaseDictionary: TIntegerDictionary;
  IntroList, Baselist, TempFilesList: TStringList;
  I, I2: Integer;
  SR: TSearchRec;
  Introname: String;
  iCounterPerSec: TLargeInteger;
  C1, C2: TLargeInteger;
begin
  try
    IntroDictionary := TSparseWideStringArray.Create;
    BaseDictionary := TIntegerDictionary.Create;
    IntroList := TStringList.Create;
    Baselist := TStringList.Create;
    TempFilesList := TStringList.Create;
    if FindFirst(extractfilepath(paramstr(0)) + '*.txt', faAnyFile, SR) = 0 then
      begin
        Introname := extractfilepath(paramstr(0)) + SR.name;
        IntroList.LoadFromFile(Introname);
        WriteLn('Количество строк в файле: ' + IntToStr(IntroList.Count));
        for I := 0 to IntroList.Count - 1 do
          IntroDictionary[I] := IntroList[I];
        IntroList.Clear;
        FindClose(SR);
        QueryPerformanceFrequency(iCounterPerSec);
        QueryPerformanceCounter(C1);
        if FindFirst(extractfilepath(paramstr(0)) + '\Files\*.txt', faAnyFile, SR) = 0 then
          begin
            repeat
              if (SR.name <> '.') and (SR.name <> '..') then
                TempFilesList.Add(extractfilepath(paramstr(0)) + '\Files\' + SR.name);
            until FindNext(SR) <> 0;
            FindClose(SR);
          end;
        if TempFilesList.Count > 0 then
          begin
            WriteLn('Всего файлов: ' + IntToStr(TempFilesList.Count));
            for I := 0 to TempFilesList.Count - 1 do
              begin
                BaseDictionary.Clear;
                Baselist.Clear;
                Baselist.LoadFromFile(TempFilesList[I]);
                for I2 := 0 to Baselist.Count - 1 do
                  BaseDictionary[Baselist[I2]] := I2;
                Baselist.Clear;
                for I2 := IntroDictionary.Count - 1 downto 0 do
                  if IntroDictionary.HasItem(I2) then
                    if BaseDictionary.HasKey(IntroDictionary[I2]) = True then
                      IntroDictionary.Delete(I2);
                WriteLn('Готово ' + IntToStr(I + 1) + ' из ' + IntToStr(TempFilesList.Count));
                if IntroDictionary.Count = 0 then
                  Break;
              end;
            if IntroDictionary.Count > 0 then
              for I := 0 to IntroDictionary.Count - 1 do
                if IntroDictionary.HasItem(I) then
                  IntroList.Add(IntroDictionary[I]);
            IntroList.SaveToFile(StringReplace(Introname, '.txt', '_compare.txt', [rfReplaceAll]));
          end
        else
          WriteLn('Не найдены файлы');
        QueryPerformanceCounter(C2);
        WriteLn('Завершено! Уникальных комбинаций: ' + IntToStr(IntroList.Count) + '; Времени потрачено на операцию: ' + FormatFloat('0.0000', (C2 - C1) / iCounterPerSec) + ' сек.');
      end
    else
      WriteLn('Файл не найден..');
    Readln;
  finally
    FreeAndNil(IntroDictionary);
    FreeAndNil(BaseDictionary);
    FreeAndNil(IntroList);
    FreeAndNil(Baselist);
    FreeAndNil(TempFilesList);
  end;

end.
Сторонняя библиотека: Fundamentals5
Найти не затруднит.. Хочу избавиться от этого тупого преобразования из TStringList в массивы.. Очень радует скорость сортировки в этих массивах и отказываться от них не буду. Задача: ускорить процесс загрузки файлов. Код еще тест версии, прошу не плеваться. Сверяет файл со другими файлами из папки files и выдает результат в виде списка строк, которых нет в файлах из папки Files. Хочу перепробовать все методы и найти самый быстрый
darkwellroad вне форума Ответить с цитированием
Старый 28.02.2018, 22:22   #7
min@y™
Цифровой кот
Старожил
 
Аватар для min@y™
 
Регистрация: 29.08.2014
Сообщений: 7,656
По умолчанию

Да не буду я читать код. Я ваще в этом не шарю.


На вопрос ответь.
Расскажу я вам, дружочки, как выращивать грибочки: нужно в поле утром рано сдвинуть два куска урана...
min@y™ вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
построчное чтение из файла в winexec Musihina1 Общие вопросы Delphi 1 11.04.2017 22:59
Построчное чтение из файла. Winapi. Си. FULEREN Общие вопросы C/C++ 9 23.08.2014 16:25
Построчное чтение из файла используя TStringList Guneska Помощь студентам 6 02.03.2013 18:07
Построчное чтение переменных из файла biohazard120 Общие вопросы C/C++ 2 04.12.2012 18:42
Построчное чтение из файла Mihalich1988 Общие вопросы C/C++ 5 17.12.2008 02:10