Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.95/21: Рейтинг темы: голосов - 21, средняя оценка - 4.95
5 / 5 / 2
Регистрация: 25.01.2015
Сообщений: 134
1

Нужно заменить значения в 16-ричном коде

26.01.2015, 00:04. Показов 3959. Ответов 53
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Передо мной стоит задача, мне надо в определённом файле, при нажатии на кнопку заменить несколько байтов, как это сделать я не имею не малейшего понятия, много лазил в интернете, нечего не нашёл. Я вообще не как не могу понять как работать с байтами. Помогите я уже устал искать.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.01.2015, 00:04
Ответы с готовыми решениями:

Замена символов в 16-ричном HEX коде программы
Всем привет! Ребята Хелп подскажите пожалуйста как заменить какой командой вот эти три позиции ...

Нужно чтобы на экран числа выводились в 16-ричном формате
В кратце: пишу CAN-месенджер в принципе он работает, но есть одно НО. Мне нужно чтобы на экран...

В 16-ричном числе выделить маской старший разряд и заменить его предопределенным числом
Как в 16ричном числе выделить маской старший разряд и заменить его предопределенным числом? То есть...

Вывести в консоль в виде таблицы значения чисел в 16 и 10-ричном формате
Обьясните пожалуйста задание, и как его можно реализовать, выучили указатели. Задание:–виведення...

53
пофигист широкого профиля
4733 / 3167 / 859
Регистрация: 15.07.2013
Сообщений: 18,252
26.01.2015, 02:11 2
Цитата Сообщение от Kaylan Посмотреть сообщение
Я вообще не как не могу понять как работать с байтами.
Надо менять учебное заведение, если так.
0
5 / 5 / 2
Регистрация: 25.01.2015
Сообщений: 134
26.01.2015, 18:15  [ТС] 3
ММ а по другому не как? Я просто знаю,в принципе как загрузить например в мемо весь шестнадцатеричный код(но связи с размером файла этот код не вводится, сильно лагает). Мне бы для начала хотя бы это сделать"Загрузить определённый отрезок байтов в например мемо" А от этого я уже смог бы отталкиваться. Помогите пожалуйста не пишите чепуху, я весь интернет облазил ничего не нашёл, вы моя последняя надежда(.
0
2664 / 2270 / 279
Регистрация: 24.12.2010
Сообщений: 13,723
26.01.2015, 19:54 4
Цитата Сообщение от Kaylan Посмотреть сообщение
Я просто знаю,в принципе как загрузить например в мемо весь шестнадцатеричный код
Ну так продемонстрируй в коде свои "простовпринципезнания"..
Допустим файл небольшой..
0
72 / 73 / 23
Регистрация: 14.10.2013
Сообщений: 547
26.01.2015, 21:04 5
В Вашем случае совсем не надо грузитт файл в мемо, а менять файл именно на те байты, которые известны.
0
5 / 5 / 2
Регистрация: 25.01.2015
Сообщений: 134
26.01.2015, 22:03  [ТС] 6
Цитата Сообщение от mss Посмотреть сообщение
Ну так продемонстрируй в коде свои "простовпринципезнания"..
Допустим файл небольшой..
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
procedure TForm1.Button1Click(Sender: TObject);
var
  f: file of byte;
  b: byte;
begin
  memo1.Clear;
  assignfile(f, 'D:\1.bmp');
  reset(f);
  while (not EOF(f)) do
  begin
    read(f, b);
    memo1.Text:=memo1.Text+inttohex(b, 2)+' ';
  end;
  closefile(f);
Не судите строго если есть ошибки так как я мало о байтах знаю, и в делфи я недавно.

Добавлено через 47 секунд
Цитата Сообщение от FaTaL-CS Посмотреть сообщение
В Вашем случае совсем не надо грузитт файл в мемо, а менять файл именно на те байты, которые известны.
В этом и суть "Как!"
0
пофигист широкого профиля
4733 / 3167 / 859
Регистрация: 15.07.2013
Сообщений: 18,252
26.01.2015, 23:03 7
Цитата Сообщение от Kaylan Посмотреть сообщение
В этом и суть "Как!"
FileSeek тебе поможет, если знаешь адрес нужного байта.
0
5705 / 2296 / 466
Регистрация: 20.11.2009
Сообщений: 7,720
Записей в блоге: 1
26.01.2015, 23:12 8
например можно вот так вот это сделать, я про замену байтов на определенной позиции

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
program Project1;
 
{$APPTYPE CONSOLE}
 
uses
  SysUtils, Classes;
var ST: TStream;
    FName: String;
    Str: String;
    Str2: String;
    c: Char;
begin
  FName := 'C:\123.dat';
  ST := TFileStream.Create(FName, fmCreate);
 
  Str := 'Hello world';
  // пишем сперва в файл что-то, я выбрал строку...
  ST.WriteBuffer(Pointer(Str)^, Length(Str) * SizeOf(Str[1]));
//----------------------------------------------------------------
  // сдвигаемся вначало, и читаем оттуда
  ST.Position := 0;
  SetLength(Str2, Length(Str));
  ST.ReadBuffer(Pointer(Str2)^, Length(Str2) * SizeOf(Str2[1]));
 
  Writeln(Str2);
 
  // сдвигаемся в 3 "позицию" и пишем туда X,
  //конечно позиция додна быть годной, я тут никаких проверок по этому поводу не делал..
  ST.Position := SizeOf(Char) * 3;
  c := 'X';
  ST.WriteBuffer(c, SizeOf(Char));
//----------------------------------------------------------------
  // сдвигаемся вначало, и читаем оттуда
  ST.Position := 0;
  SetLength(Str2, Length(Str));
  ST.ReadBuffer(Pointer(Str2)^, Length(Str2) * SizeOf(Str2[1]));
 
  Writeln(Str2);
 
  ST.Position := SizeOf(Char) * 6;
  c := 'Y';
  ST.WriteBuffer(c, SizeOf(Char));
//----------------------------------------------------------------
  // сдвигаемся вначало, и читаем оттуда
  ST.Position := 0;
  SetLength(Str2, Length(Str));
  ST.ReadBuffer(Pointer(Str2)^, Length(Str2) * SizeOf(Str2[1]));
 
  Writeln(Str2);
 
  ST.Free;
  Readln;
end.
1
13104 / 5885 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
27.01.2015, 00:17 9
В продолжение темы. Ещё 2 примера.

Цитата Сообщение от Kaylan Посмотреть сообщение
Передо мной стоит задача, мне надо в определённом файле, при нажатии на кнопку заменить несколько байтов
Предположим, в файл со смещением 9 надо записать 5 смежных байт. Смещение означает - сколько байт расположено слева от нужной позиции. Поэтому смещение 0 соответствует первому байту файла. А смещение 9 соответствует позиции, на которой расположен 10-й байт. Для перехода к заданному смещению в файле предназначена процедура Seek(). Если используется файловый поток типа TFileStream, то к заданному смещению можно перейти, записав нужное значение в свойство TFileStream.Position.
Действовать будем так:
1. Создадим массив из 5 байт.
2. Запишем в него нужные значения байтов.
3. Откроем файл и переведём файловый указатель на позицию, соответствующую смещению 9 (это 10-й байт, считая от начала файла).
4. Запишем в файл, начиная с текущей позиции, содержимое массива - т. е. 5 заданных байт.

С использованием процедуры BlockWrite():
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//Запись в файл нескольких смежных байт по заданному смещению.
//С использованием процедуры BlockWrite().
procedure TForm1.Button1Click(Sender: TObject);
var
  F : File;
  FileName : String;
  Arr : array of Byte;
begin
  //Выделяем память для массива.
  SetLength(Arr, 5);
  //Записываем в массив значения байтов.
  Arr[0] := $41;
  Arr[1] := $42;
  Arr[2] := $43;
  Arr[3] := $44;
  Arr[4] := $45;
 
  //Путь к файлу, который надо обработать.
  FileName := ExtractFilePath(ParamStr(0)) + 'file.dat';
  //Связываем файловую переменную с именем файла.
  AssignFile(F, FileName);
  //Открываем файл в режиме чтение/запись. При этом задаём размер наименьшего
  //блока доступа равным 1-му байту.
  Reset(F, 1);
  try
    //Проверяем - достаточный ли размер файла. Размер файла выражается в количестве
    //наименьших блоков доступа. Мы открывали файл с наименьшим блоком доступа = 1 байт,
    //поэтому получим размер файла в байтах.
    if FileSize(F) < 9 + Length(Arr) then
    begin
      ShowMessage('Внимание! Размер файла недостаточный. Действие отменено.');
      Exit; //При этом управление сначала перейдёт в раздел finally - end.
    end;
    //Переходим по смещению = 9.
    Seek(F, 9);
    //Начиная с текущей позиции, записываем в файл содержимое массива.
    BlockWrite(F, Arr[0], Length(Arr));
  finally
    CloseFile(F); //Закрываем файл.
  end;
end;
С использованием файлового потока типа TFileStream:
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//Запись в файл нескольких смежных байт по заданному смещению.
//С использованием файлового потока типа TFileStream.
procedure TForm1.Button1Click(Sender: TObject);
var
  Fs : TFileStream;
  FileName : String;
  Arr : array of Byte;
begin
  //Выделяем память для массива.
  SetLength(Arr, 5);
  //Записываем в массив значения байтов.
  Arr[0] := $41;
  Arr[1] := $42;
  Arr[2] := $43;
  Arr[3] := $44;
  Arr[4] := $45;
 
  //Путь к файлу, который надо обработать.
  FileName := ExtractFilePath(ParamStr(0)) + 'file.dat';
  //Создаём экземпляр файлового потока и открываем файл в режиме записи (fmOpenWrite)
  //с запретом на запись другим процессам (fmShareDenyWrite). Если надо открыть
  //файл в режиме чтение/запись, то следует использовать константу fmOpenReadWrite.
  Fs := TFileStream.Create(FileName, fmOpenWrite + fmShareDenyWrite);
  try
    //Проверяем - достаточный ли размер файла.
    if Fs.Size < 9 + Length(Arr) then
    begin
      ShowMessage('Внимание! Размер файла недостаточный. Действие отменено.');
      Exit; //При этом управление сначала перейдёт в раздел finally - end.
    end;
    //Переходим по смещению = 9.
    Fs.Position := 9;
    //Начиная с текущей позиции, записываем в файловый поток содержимое массива.
    Fs.Write(Arr[0], Length(Arr));
  finally
    FreeAndNil(Fs); //Уничтожаем экземпляр потока и закрываем файл.
  end;
end;
Если содержимое файла такое:
12345678900000123456789
то в результате выполнения любого из выше приведённых кодов содержимое файла поменяется таким образом:
123456789ABCDE123456789
Добавлено через 22 минуты
Содержимое файла показано так, как оно выглядит в текстовом редакторе с ANSI кодировкой.
Например, ANSI кодовая страница CP1251 (Windows-1251). Первая половина этой таблицы совпадает с таблицей ASCII - там заданы десятичные цифры, буквы латиницы и пр.
2
5 / 5 / 2
Регистрация: 25.01.2015
Сообщений: 134
27.01.2015, 01:30  [ТС] 10
Огромное всем спасибо, хоть что-то начал понимать, но вопрос не закрыт, по возникновении вопросов буду писать сюда)

Добавлено через 36 минут
А как отправить поиск по файлу(16-ричном коде) например мне надо найти вот такую комбинацию 5c 33 64 ab 31 de 0b 26 2d 9a 12 8b 3b 3e 55 3e и уже в этой комбинации менять байты как это сделать? А за ответы спасибо очень вам благодарен!
0
пофигист широкого профиля
4733 / 3167 / 859
Регистрация: 15.07.2013
Сообщений: 18,252
27.01.2015, 01:57 11
Цитата Сообщение от Kaylan Посмотреть сообщение
А как отправить поиск по файлу(16-ричном коде) например мне надо найти вот такую комбинацию
Вот так и знал, что проблема именно в том как найти те байты, которые нужно заменить.

Ищи в И-нете реализацию Boyer-Moore-Horspool алгоритма.
P.S. Возможно с тех пор когда мне нужен был такой поиск придумали другой более быстрый алгоритм.
0
13104 / 5885 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
27.01.2015, 15:38 12
Лучший ответ Сообщение было отмечено Kaylan как решение

Решение

Скорее всего, автора устроит простой алгоритм поиска. По крайней мере, до сих пор не были обозначены какие-то особенные требования к скорости обработки. Поэтому вполне можно воспользоваться функцией Pos() или PosEx().
Цитата Сообщение от Kaylan Посмотреть сообщение
А как отправить поиск по файлу(16-ричном коде)
Можно поступить так - загружаем содержимое файла в ANSI строку. И в этой строке выполняем поиск подстроки с помощью функции Pos() или PosEx(). Подстрокой будет другая ANSI строка, которая содержит искомую последовательность байтов. Полученную позицию используем для записи новых данных в файл. Если размер файла очень большой, то можно организовать его обработку по частям. И можно организовать замену всех вхождений заданного шаблона, если нужно.

Пример для случая, когда весь файл можно загрузить в память и когда нужно заменить только первое вхождение.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//Поиск первого вхождения и замена данных в файле. Для файлов, которые можно полностью загрузить в память.
procedure TForm1.Button1Click(Sender: TObject);
var
  Fs : TFileStream;
  FileName : String;
  Sf, Sr, SBuff : AnsiString; //AnsiString - тип, описывающий строку однобайтных символов.
  Offs : Int64;
begin
  Sf := #$56#$57#$58#$59#$5A; //= 'VWXYZ'. //Последовательность искомых байт.
  Sr := #$41#$42#$43#$44#$45; //= 'ABCDE'. //Последовательность заменяющих байт.
 
  FileName := ExtractFilePath(ParamStr(0)) + 'file.dat'; //Путь к файлу.
  //Создаём экземпляр файлового потока и открываем файл в режиме чтения и записи
  //(fmOpenReadWrite), с запретом на запись из других процессов (fmShareDenyWrite).
  Fs := TFileStream.Create(FileName, fmOpenReadWrite + fmShareDenyWrite);
  try
    SetLength(SBuff, Fs.Size); //Выделяем память для буфера.
    Fs.Read(SBuff[1], Length(SBuff)); //Загружаем в буфер данные файлового потока.
    //Поиск в буфере SBuff первого вхождения подстроки Sf. Результат получаем в виде смещения.
    Offs := Pos(Sf, SBuff) - 1;
    if Offs > -1 then //Если подстрока найдена.
    begin
      Fs.Position := Offs; //Перемещаем указатель потока к найденной подстроке.
      Fs.Write(Sr[1], Length(Sr)); //Записываем новую последовательность байтов.
    end;
  finally
    FreeAndNil(Fs); //Уничтожаем экземпляр файлового потока и закрываем файл.
  end;
 
  if Offs > -1 then
    ShowMessage('Заданная последовательность байт найдена. Смещение = ' + IntToStr(Offs)
      + '. Записано новое содержимое.')
  else
    ShowMessage('Заданная последовательность байт не найдена.');
end;
Содержимое файла до обработки:
123456789VWXYZ123456789
123456789VWXYZ123456789
Содержимое файла после обработки:
123456789ABCDE123456789
123456789VWXYZ123456789
1
72 / 73 / 23
Регистрация: 14.10.2013
Сообщений: 547
27.01.2015, 21:14 13
Mawrat, Оффтоп конечно, но Вам надо книжки писать или преподавать.
0
5 / 5 / 2
Регистрация: 25.01.2015
Сообщений: 134
27.01.2015, 21:27  [ТС] 14
Цитата Сообщение от FaTaL-CS Посмотреть сообщение
Mawrat, Оффтоп конечно, но Вам надо книжки писать или преподавать.
Согласен!!! Огромное ему спасибо он мне реально помог очень.

Добавлено через 10 минут
И последнее я конечно видел как делать, но не очень понял помогите мне нужно, что бы указывать не определённый файл вот здесь
Delphi
1
FileName := ExtractFilePath(ParamStr(0)) + 'file.dat';
А расширение или тип я точно не знаю вообщем то, что идёт после точки, что бы во всех файлов(указанного пути), выполнял процедуру, которая выше. Например расширение ".ini". Смотрел в других местах, там написано, что нужно писать, но я не понял куда.
0
13104 / 5885 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
28.01.2015, 05:23 15

Не по теме:

Цитата Сообщение от FaTaL-CS Посмотреть сообщение
Mawrat, Оффтоп конечно, но Вам надо книжки писать или преподавать.
Благодарю. :)


Цитата Сообщение от Kaylan Посмотреть сообщение
Например расширение ".ini".
Возможно, мы зря тут с байтами возимся. Если надо работать с INI файлами - для этого есть специальные классы: TIniFile и TMemIniFile из модуля IniFiles.
Цитата Сообщение от Kaylan Посмотреть сообщение
мне нужно, что бы указывать не определённый файл вот здесь ...
А расширение или тип я точно не знаю вообщем то, что идёт после точки, что бы во всех файлов(указанного пути), выполнял процедуру, которая выше.
Чтобы перебрать все файлы по заданной маске имён - для этого можно использовать функции FindFirst()/FindNext()/FindClose().
Пример: Поиск текстовых файлов, которые содержат заданное слово. Найденные файлы переместить в другую папку.
В этом примере перебор файлов идёт в заданной папке и во всех вложенных в неё папках.
0
5 / 5 / 2
Регистрация: 25.01.2015
Сообщений: 134
28.01.2015, 14:43  [ТС] 16
Цитата Сообщение от Mawrat Посмотреть сообщение

Не по теме:


Благодарю. :)



Возможно, мы зря тут с байтами возимся. Если надо работать с INI файлами - для этого есть специальные классы: TIniFile и TMemIniFile из модуля IniFiles.

Чтобы перебрать все файлы по заданной маске имён - для этого можно использовать функции FindFirst()/FindNext()/FindClose().
Пример: Поиск текстовых файлов, которые содержат заданное слово. Найденные файлы переместить в другую папку.
В этом примере перебор файлов идёт в заданной папке и во всех вложенных в неё папках.
Нет, не ини я как пример привёл. Там другое расширение.

Именно что бы расширение было (не то что внутри файла) у меня есть определённое расширение, в определённой папке лежат около сотни файлов с таким расширением, и в них во всех есть одна последовательность байтов но имеют разное смещение, мне нужно преобразовать эти байты именно во ВСЕХ файлах в папке.
0
13104 / 5885 / 1706
Регистрация: 19.09.2009
Сообщений: 8,808
29.01.2015, 11:28 17
Цитата Сообщение от Kaylan Посмотреть сообщение
у меня есть определённое расширение, в определённой папке лежат около сотни файлов с таким расширением, и в них во всех есть одна последовательность байтов но имеют разное смещение, мне нужно преобразовать эти байты именно во ВСЕХ файлах в папке.
Поиск и замена цепочек байт в файлах заданного директория. С обработкой ошибок. Поиск файлов построен на вызовах FindFirst()/FindNext()/FindClose(). Если параметр aSubDir = True, то поиск файлов выполняется также во вложенных директориях. В каждом файле выполняется поиск и замена всех вхождений заданной цепочки - используется функция PosEx() из модуля SysUtils.

Следует учитывать следующее. В файловой системе каждому имени файла сопоставляется короткое имя. А функции FindFirst()/FindNext() выполняют поиск по обеим версиям имён (по длинному и короткому). В результате этого может произойти, например, следующая ситуация. Если задали такую маску поиска: *.exe, то будут найдены файлы со следующими расширениями: *.exe, *.exec, *.executable. Это происходит потому, что файлам с расширениями *.exec, *.executable соответствуют короткие имена, в которых расширение оказывается равным *.exe. Такая особенность относится также к ряду других расширений. Поэтому, если надо точно учитывать расширения, то надо в код добавить дополнительную проверку расширений.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
uses
  FileCtrl, StrUtils;
 
{Функция выполняет поиск в файле aFileName заданной цепочки байт aSf и вставку
на найденных позициях заменяющей цепочки байт aSr.
При успешном выполнении функция возвращает значение = True, иначе - False.
В список aSl записывается журнал выполнения. Запись в журнал будет отменена,
если aSl = nil.
aPref - задаёт префикс в строках, которые выводятся в журнал. Например, через
aPref можно задать отступ: ' '.}
function ProcFile(const aFileName : String; const aSf, aSr : AnsiString;
  aSl : TStrings; const aPref : String) : Boolean;
const
  SelfName = 'ProcFile()';
  //Размер буфера в байтах. Этот размер не должен быть меньше размера искомой подстроки.
  SizeBuff = 100000;
var
  Fs : TFileStream;
  SBuff : AnsiString; //AnsiString - тип, описывающий строку однобайтных символов.
  FOffs, Offs, SizeRes, Cnt : Int64;
begin
  Result := False;
  //Проверки.
  if Length(aSf) <> Length(aSr) then
    raise Exception.Create(SelfName + '. Длины aSf и aSr отличаются.');
  if SizeBuff < Length(aSf) then
    raise Exception.Create(SelfName + '. Размер буфера меньше длины aSf.');
 
  //Создаём экземпляр файлового потока и открываем файл в режиме чтения и записи
  //(fmOpenReadWrite), с запретом на запись из других процессов (fmShareDenyWrite).
  try
    Fs := TFileStream.Create(aFileName, fmOpenReadWrite + fmShareDenyWrite);
  except
    on e: Exception do
    begin
      if Assigned(aSl) then
        aSl.Add(aPref + 'Ошибка! Не удалось открыть файл. Сообщение: ' + e.Message);
      Exit;
    end;
  end;
  //Обработка данных потока (файла).
  try
    try
      SetLength(SBuff, SizeBuff); //Выделяем память для буфера.
      Cnt := 0;   //Количество выполненных замен.
      FOffs := 0; //Смещение указателя потока до чтения очередного блока данных.
      repeat
        SizeRes := Fs.Read(SBuff[1], SizeBuff); //Загружаем в буфер данные файлового потока.
        if SizeRes < SizeBuff then //Если в буфер загружено менее, чем SizeBuff байт (при достижении конца потока).
          SetLength(SBuff, SizeRes); //Изменяем размер буфера в соответствии с количеством загруженных байт.
        //Поиск в буфере.
        Offs := PosEx(aSf, SBuff, 1) - 1; //Смещение искомой подстроки в буфере.
        while Offs > -1 do
        begin
          Inc(Cnt); //Количество выполненных замен.
          Fs.Position := FOffs + Offs; //Перемещаем указатель потока к найденной подстроке.
          Fs.Write(aSr[1], Length(aSr)); //Записываем новую последовательность байтов.
          Offs := PosEx(aSf, SBuff, Offs + 2) - 1; //Продолжаем поиск в буфере со следующей позиции.
        end;
        FOffs := FOffs + SizeRes; //Смещение указателя потока с учётом последнего прочитанного блока.
        if FOffs < Fs.Size then   //Если пока не дошли до конца файла.
          Dec(FOffs, Length(aSf) - 1); //Откатываем смещение к неисследованной области.
        Fs.Position := FOffs;
      until Fs.Position = Fs.Size; //Прекращаем поиск, если достигли конца потока.
    except
      on e: Exception do
      begin
        if Assigned(aSl) then
          aSl.Add(aPref + 'Ошибка! Исключение возникло при обработке файла. Сообщение: ' + e.Message);
        Exit; //При этом управление сначала перейдёт в раздел finally - end.
      end;
    end;
  finally
    FreeAndNil(Fs); //Уничтожаем экземпляр файлового потока и закрываем файл.
  end;
 
  if Assigned(aSl) then
    aSl.Add(aPref + 'Количество замен: ' + IntToStr(Cnt));
  Result := True;
end;
 
{Процедура в заданном директории aPath (и во всех вложенных директориях, при aSubDir = True)
находит файлы по заданной маске aMask и в найденных файлах выполняет замену всех
вхождений цепочки байт aSf на цепочку aSr.
Если маска не задана, то будет использована маска = '*'.
Сведения о выполненных действиях выводятся в журнал aSl.
aSubDir - True, если надо обработать вложенные директории, False - иначе.}
procedure ProcDir(const aPath, aMask : String; const aSf, aSr : AnsiString;
  aSl : TStrings; const aSubDir : Boolean);
var
  Path, Mask : String;
  Srch : TSearchRec;
  Attr : Integer;
begin
  //Добавляем в конец строки слеш, если его нет.
  Path := IncludeTrailingPathDelimiter(aPath);
  //Маска.
  if aMask <> '' then
    Mask := aMask
  else
    Mask := '*';
 
  //В текущем директории ищем файлы по заданной маске.
  aSl.Add('Папка: ' + Path);
  Attr := faAnyFile - faVolumeID - faDirectory;
  if FindFirst(Path + Mask, Attr, Srch) = 0 then
  try
    repeat
      aSl.Add('    Файл: ' + Srch.Name);
      ProcFile(Path + Srch.Name, aSf, aSr, aSl, '        ');
    until FindNext(Srch) <> 0;
  finally
    FindClose(Srch);
  end;
 
  if aSubDir then //Если нужно обработать вложенные директории.
  begin
    //В текущем директории ищем все вложенные директории и для каждого из них выполняем рекурсивный вызов.
    Attr := faDirectory;
    if FindFirst(Path + '*', Attr, Srch) = 0 then
    try
      repeat
        if (Srch.Attr and Attr = Attr) and (Srch.Name <> '.') and (Srch.Name <> '..') then
          ProcDir(Path + Srch.Name, Mask, aSf, aSr, aSl, aSubDir);
      until FindNext(Srch) <> 0;
    finally
      FindClose(Srch);
    end;
  end;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
  S, Path, Mask : String;
  Sf, Sr : AnsiString;
begin
  //Директорий, в котором лежит исполняемый файл программы.
  Path := ExtractFilePath(ParamStr(0));
  //Диалог выбора директория.
  if not SelectDirectory('Выбор папки', '', Path) then
    Exit;
  {
  if not SelectDirectory(Path, [sdAllowCreate, sdPerformCreate, sdPrompt], 0) then
    Exit;
  }
  //Проверка существования директория.
  if not DirectoryExists(Path) then
  begin
    MessageBox(Handle, 'Заданная папка не найдена. Действие отменено.', 'Отмена!',
      MB_OK + MB_ICONWARNING + MB_APPLMODAL);
    Exit;
  end;
 
  //Маска имён файлов.
  Mask := Edit1.Text;
  if Mask = '' then
    Mask := '*';
 
  {Искомая и заменяющая цепочки байт. Они должны быть заданы в виде шестнадцатиричных
  кодов. Каждый байт должен быть пердставлен двумя шестнадцатиричными цифрами.
  Запись должна быть без пробелов и состоять только из шестнадцатиричных цифр.
  Пример: 4B4C4D4E Этому значению, согласно таблице ASCII соответствует строка: KLMN }
 
  //Искомая цепочка байт.
  S := Edit2.Text;
  SetLength(Sf, Length(S) div 2);
  HexToBin(PChar(S), PAnsiChar(Sf), Length(Sf));
  //Заменяющая цепочка байт.
  S := Edit3.Text;
  SetLength(Sr, Length(S) div 2);
  HexToBin(PChar(S), PAnsiChar(Sr), Length(Sr));
 
  //Проверки.
  if Length(Sf) <> Length(Sr) then
  begin
    MessageBox(Handle, 'Длины искомой и заменяющей цепочек различны. Действие отменено.',
      'Отмена!', MB_OK + MB_ICONWARNING + MB_APPLMODAL);
    Exit;
  end;
  if Sf = '' then
  begin
    MessageBox(Handle, 'Искомая цепочка не задана. Действие отменено.',
      'Отмена!', MB_OK + MB_ICONWARNING + MB_APPLMODAL);
    Exit;
  end;
 
  Memo1.Text := 'Начальный директорий: ' + Path;
  Memo1.Lines.Add('Маска: "' + Mask + '"');
  Memo1.Lines.Add('Искомая цепочка байт, HEX:'#9 + Edit2.Text);
  Memo1.Lines.Add('Заменяющая цепочка байт, HEX:'#9 + Edit3.Text);
  Memo1.Lines.Add('----------');
 
  ProcDir(Path, Mask, Sf, Sr, Memo1.Lines, True); //Поиск и обработка файлов.
  Memo1.Lines.Add('----------');
end;
 
end.
Вложения
Тип файла: 7z SearchAndProcFiles-01.7z (163.5 Кб, 8 просмотров)
0
5705 / 2296 / 466
Регистрация: 20.11.2009
Сообщений: 7,720
Записей в блоге: 1
29.01.2015, 12:09 18
Цитата Сообщение от Kaylan Посмотреть сообщение

Не по теме:

Согласен!!! Огромное ему спасибо он мне реально помог очень.

Не по теме:

Да и не только вам :), благодаря этому человеку я вообще программирую, вытащил он меня в свое время из того, во что я увяз.

Цитата Сообщение от FaTaL-CS Посмотреть сообщение

Не по теме:

Mawrat, Оффтоп конечно, но Вам надо книжки писать или преподавать

.

Не по теме:

ну, мы же ничего о нем не знаем ), вдруг он это уже делает на самом деле, а тут под прикрытием своего ника только :)))

0
Mawrat
29.01.2015, 12:41
  #19

Не по теме:

Цитата Сообщение от Arcor Посмотреть сообщение
ну, мы же ничего о нем не знаем ), вдруг он это уже делает на самом деле, а тут под прикрытием своего ника только :)))
На проекте, бывает, требуется подучить кого-нибудь. В этом смысле можно считать, что немного преподаю. :) Будет время и книги напишем. :D То ли ещё будет...

0
5 / 5 / 2
Регистрация: 25.01.2015
Сообщений: 134
29.01.2015, 22:30  [ТС] 20
Спасибо всем огромное в большей степени Mawrat-у за подробное объяснение и за коды, без него я так бы и ходил в просторах интернета так и нечего не узнав, я очень рад что написал СЮДА этот вопрос.

Добавлено через 5 часов 34 минуты
А можно ли как нибудь все найденные файлы загрузить так что бы это вообще не было видно например в стринглист или куда ещё. PS
Цитата Сообщение от Mawrat Посмотреть сообщение
Если задали такую маску поиска: *.exe, то будут найдены файлы со следующими расширениями: *.exe, *.exec, *.executable. Это происходит потому, что файлам с расширениями *.exec, *.executable соответствуют короткие имена, в которых расширение оказывается равным *.exe. Такая особенность относится также к ряду других расширений. Поэтому, если надо точно учитывать расширения, то надо в код добавить дополнительную проверку расширений.
вот это мне не обязательно, такая проблема у меня не возникнет. Извините если туплю но не как не могу сообразить.
0
29.01.2015, 22:30
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.01.2015, 22:30
Помогаю со студенческими работами здесь

Нужно заменить тернарный оператор на циклы в готовом коде
Здравствуйте, нужно написать игру с такими условиями :Это игра, в которую могут играть два игрока в...

Значения в матрице. Нужно разобраться в коде с++ человеку не знающему языка
Добрый день. На просторах интернета нашел программу, она уравнивает химическую реакцию в переданной...

Что нужно поменять в коде чтобы значения в матрице были вещественные?
Что нужно поменять в коде чтобы значения в матрице были вещественные? #include &lt;stdio.h&gt;...

Нужно чтобы программа открывала Developer Tool и меняла некоторый значения в коде страницы
Здравствуйте, в браузере Google Chrome есть такая функция, называется она Developer Tool, которая...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru