Добавить данные в файл формата .exe и получить их обратно

Имеется список exe файлов, небольшого размера.

Пример, список:

1.exe
2.exe
3.exe

Нужно в конце каждого из низ в добавить данные, в виде Hex строки. В Memo1 расположен текст.

2010
2011
2012

Нужно записать каждое из значений из memo в конце каждого exe файла - что бы на выходе получилось:

Папка с Именем "2010"

И в неё скопированы три файла **1.exe, 2.exe, 2.exe** (в каждом из которых в Hex (в конце) - добавлена строка **2010** ). 

Папка с Именем "2011"

И в неё скопированы три файла **1.exe, 2.exe, 2.exe** (в каждом из которых в Hex (в конце) - добавлена строка **2011** ). 

Папка с Именем "2012"

И в неё скопированы три файла **1.exe, 2.exe, 2.exe** (в каждом из которых в Hex (в конце)  - добавлена строка **2012** ). 

У меня есть код вот такого плана и он делает изменения только в одном файле. Прошу помощи в решении данного вопроса:

function AttachToFile(const AFileName: string;
  MemoryStream: TMemoryStream): Boolean;
var
  aStream: TFileStream;
  iSize: Integer;
begin
  Result := False;
  if not FileExists(AFileName) then
    Exit;
  try
    aStream := TFileStream.Create(AFileName, fmOpenWrite or fmShareDenyWrite);
    MemoryStream.Seek(0, soFromBeginning);
    aStream.Seek(0, soFromEnd);
    aStream.CopyFrom(MemoryStream, 0);
    iSize := MemoryStream.Size + SizeOf(Integer);
    aStream.Write(iSize, SizeOf(iSize));
  finally
    aStream.Free;
  end;
  Result := True;
end;

function LoadFromFile(const AFileName: string; MemoryStream: TMemoryStream)
  : Boolean;
var
  aStream: TFileStream;
  iSize: Integer;
begin
  Result := False;
  if not FileExists(AFileName) then
    Exit;

  try
    aStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
    aStream.Seek(-SizeOf(Integer), soFromEnd);
    aStream.Read(iSize, SizeOf(iSize));
    if iSize > aStream.Size then
    begin
      aStream.Free;
      Exit;
    end;

    aStream.Seek(-iSize, soFromEnd);
    MemoryStream.SetSize(iSize - SizeOf(Integer));
    MemoryStream.CopyFrom(aStream, iSize - SizeOf(iSize));
    MemoryStream.Seek(0, soFromBeginning);
  finally
    aStream.Free;
  end;
  Result := True;
end;

// А тут у меня идет изменения в файле, то есть перезапись
procedure TForm1.SaveClick(Sender: TObject);
var
  aStream: TMemoryStream;
begin
  aStream := TMemoryStream.Create;
  Memo1.Lines.SaveToStream(aStream);
  AttachToFile('Test.exe', aStream);
  aStream.Free;
end;

// В данном коде можно извлечь - посмотреть результат изменений
procedure TForm1.LoadClick(Sender: TObject);
var
  aStream: TMemoryStream;
begin
  aStream := TMemoryStream.Create;
  LoadFromFile('Test.exe', aStream);
  Memo1.Lines.LoadFromStream(aStream);
  aStream.Free;
end;

Ответы (1 шт):

Автор решения: Alex R.

Код, который требуется для решения задачи проще, чем уже представленный.

На входе процедуры должен быть список с полными путями к файлам, строки и стартовая директория, в которую копируются файлы.

Задача решается с использованием двух циклов, созданием директории ForceDirectories и редко используемом классе с потоком данных для строки TStringStream.

procedure StrangeCopy(AFileList: TStringDynArray; AStrList: TStrings; AStartDir: string);
var
  i, j: integer;
  vStream: TStringStream;
  vOutDir, vOutFile: string;
begin
  for i := 0 to AStrList.Count - 1 do
    begin
      vOutDir := TPath.Combine(AStartDir, AStrList[i]);
      ForceDirectories(vOutDir);

      vStream := TStringStream.Create(AStrList[i]);
      try
         for j := Low(AFileList) to High(AFileList) do
            begin
              vOutFile := TPath.Combine(vOutDir, ExtractFileName(AFileList[i]));

              TFile.Copy(AFileList[i], vOutFile);

              AttachToFile(vOutFile, vStream)
            end;
      finally
        vStream.Free;
      end;
    end;
end;  

vStream каждый раз создаю для простоты восприятия. Если его создать один раз через Create, то потребуется еще каждый раз очистить (Clear) и заполнить (WriteString)

→ Ссылка