Ru-Board.club
← Вернуться в раздел «Прикладное программирование»

» Вопросы по Delphi (до версии 2009) - часть 6

Автор: salexn1
Дата сообщения: 01.12.2012 12:59
xliker
Да все у вас правильно, просто нужно переопределить метод Loaded и туда запихнуть MoveData

procedure Loaded; override;

...
procedure TMarkTable.Loaded;
begin
inherited;
MoveData;
end;

Как-то так
Автор: R3Pa4eK
Дата сообщения: 05.12.2012 15:19
Вопрос к знатокам. Нужно организовать поиск известных сигнатур в файле. Т.е. что то типа HyperRipper, только проще. Нужно искать только wav-файлы (RIFF-WAVE). Есть код на делфи, но он не умеет работать с файлами, размер которых > 2 Gb. А для сканирования используются файлы > 6 Gb. Можно ли этот код переделать так, чтобы он хавал большие файлы?

Код:

[more]
program IFC;

{$APPTYPE CONSOLE}

uses
Windows, SysUtils, Classes, Forms;

const
bufsize = 65535;

type
TFileInfo = record
Name: AnsiString;
Size: Longint;
StartOffset: Longint;
end;

TBuffer = Array [1..bufsize] of Char;

var
Count: Integer;
List: Array[1..bufsize] of TFileInfo;
Buffer: TBuffer;
F, F2: File;
FSize, FPos, TempPos, tmpsize:longint;
Input: TFileInfo;
i: Integer;

Procedure Wave(Buffer: TBuffer; BufSize: Integer);
var i: Longint;
k: Integer;
fname: String;
Begin
for i:=1 to BufSize-12 do Begin
if buffer[i]='R' then
if buffer[i+1]='I' then
if buffer[i+2]='F' then
if buffer[i+3]='F' then
if buffer[i+8]='W' then
if buffer[i+9]='A' then
if buffer[i+10]='V' then
if buffer[i+11]='E' then Begin
Inc(Count);
Seek(F,FPos+i+3);
Blockread(F,FSize,4);
FSize:=FSize+8;
fname:=ExtractFileName('data.7z');
input.Name:='';
k:=1;
repeat
input.Name:=input.Name+fname[k];
inc(k);
until (k=8)or(fname[k]='.');
input.Name:= IntToHex(FSize, 16) + '_' + IntToHex(FPos+i-1, 16) + '.wav';
input.Size:= FSize;
input.StartOffset:=FPos+i-1;
List[count]:=input;
End;
End;
End;

begin
if not (FileExists(ParamStr(2))) then begin
WriteLn('Error! Input file was not found!');
Exit;
end;

Assignfile(F, 'data.7z');
try Reset(F,1);
except end;
FPos:=0;
Repeat
Application.ProcessMessages;
Blockread(F,Buffer,bufsize);
TempPos:=FilePos(F)-12;
Wave(Buffer,bufsize);
FPos:=FPos+65523;
Seek(f,TempPos);
Until Filepos(f)>=Filesize(f)-bufsize;
Blockread(F,Buffer,Filesize(F)-Filepos(F));
Wave(Buffer,Filesize(F)-Filepos(F));
try Closefile(F);
except end;

WriteLn('Found', Count, ' wave files!');

end.
[/more]
Автор: salexn1
Дата сообщения: 05.12.2012 15:39
R3Pa4eK
Код жгучий конечно

Одно это

Цитата:
if buffer[i]='R' then
if buffer[i+1]='I' then
if buffer[i+2]='F' then
if buffer[i+3]='F' then
if buffer[i+8]='W' then
if buffer[i+9]='A' then
if buffer[i+10]='V' then
if buffer[i+11]='E' then Begin

вызывает восторг
можно было в одну строчку через and записать - читать удобнее было бы...

По существу - попробуй заюзать
хттп://gp.17slon.com/gp/gphugefile.htm

на крайний случай спроси у гугла:

delphi how to open file more than 2GB
Автор: R3Pa4eK
Дата сообщения: 05.12.2012 16:17

Цитата:
Код жгучий конечно



Цитата:
хттп://gp.17slon.com/gp/gphugefile.htm

Хм.. Переписал код под этот компонент, получилось как то так:

[more=Код]
program test;

{$APPTYPE CONSOLE}

uses
Windows, GpHugeF, SysUtils, Forms, Classes;

const bufsize=65535;

type
TFileInfo = record
Name: AnsiString;
Size: Longint;
StartOffset: Longint;
end;

TBuffer = Array [1..bufsize] of Char;

var
Count: Integer;
List: Array[1..bufsize] of TFileInfo;
Buffer: TBuffer;
F, F2: File;
FSize, FPos, TempPos, tmpsize:longint;
Input: TFileInfo;
i: Integer;
File64: TGpHugeFile;

Procedure Wave(Buffer: TBuffer; BufSize: Integer);
var i: Longint;
k: Integer;
fname: String;
Begin
for i:=1 to BufSize-12 do Begin
if buffer[i]='R' then
if buffer[i+1]='I' then
if buffer[i+2]='F' then
if buffer[i+3]='F' then
if buffer[i+8]='W' then
if buffer[i+9]='A' then
if buffer[i+10]='V' then
if buffer[i+11]='E' then Begin
Inc(Count);
File64.Seek(FPos+i+3);
File64.BlockRead(FSize,4, HInstance);
FSize:=FSize+8;
fname:=ExtractFileName('data.pak');
input.Name:='';
k:=1;
repeat
input.Name:=input.Name+fname[k];
inc(k);
until (k=8)or(fname[k]='.');
input.Name:= IntToHex(FSize, 16) + '_' + IntToHex(FPos+i-1, 16) + '.wav';
input.Size:= FSize;
input.StartOffset:=FPos+i-1;
List[count]:=input;
End;
End;
End;

procedure SetFileSize(FileName: AnsiString; NewSize: Int64);
var fs: TFileStream;
begin
fs:= TFileStream.Create(FileName, fmOpenReadWrite);
fs.Size:= NewSize;
fs.Free;
end;

begin
File64:= TGpHugeFile.Create('data.pak');
File64.Reset(1);

FPos:=0;
Repeat
Application.ProcessMessages;
File64.BlockRead(Buffer, bufsize, HInstance);
TempPos:= File64.FilePos - 12;
Wave(Buffer, bufsize);
FPos:= FPos + bufsize;
File64.Seek(TempPos);
Until File64.FilePos >= File64.FileSize-bufsize;
File64.BlockRead(Buffer, File64.FileSize-File64.FilePos, HInstance);
Wave(Buffer, File64.FileSize-File64.FilePos);
File64.Truncate;
File64.Close;

Writeln(Count);
end.

[/more]

Wav-файлы он нашел. Но осталась прежняя проблема. Попробовал скормить ему файл, размером 5,11 ГБ (5 497 558 131 байт), программа закрылась после 20 сек. работы. Возможно это связано с тем, что bufsize=65535? Может нужно, чтобы bufsize = filesize?

Добавлено:
В общем, попробовал подставить вместо BufSize размер файла. Программа просто закрывается, видимо переполнение буффера. Даже не знаю, что делать...
Автор: R3Pa4eK
Дата сообщения: 05.12.2012 18:24
Еще заметил такую вещь. Если вместо динамически изменять размер Buffer, то появляется ошибка "Access violation at adress ... in module "test.exe" Write of adress ...". Т.е. вместо "TBuffer = Array [1..65535] of Char;" написал "TBuffer = Array of Char;", потом в коде: "SetLength(Buffer, 65535);". Что не так? О_о
Автор: ant0ni02004
Дата сообщения: 05.12.2012 19:05
R3Pa4eK
если размеры файла больше 2ГБ то все переменные-позиции должны быть int64 а не integer
также осваивайте работу через TFileStream, он умеет. а вот blockread и ему подобные чисто паскалевские i/o не способны с большими файлами работать
Автор: R3Pa4eK
Дата сообщения: 05.12.2012 19:16
ant0ni02004
Я это понял. Смотри предыдущий [more=код]
{$APPTYPE CONSOLE}

uses
Windows, GpHugeF, SysUtils, Forms, Classes;

const bufsize=65535;

type
TFileInfo = record
Name: AnsiString;
Size: Longint;
StartOffset: Longint;
end;

TBuffer = Array [1..bufsize] of Char;

var
Count: Integer;
List: Array[1..bufsize] of TFileInfo;
Buffer: TBuffer;
F, F2: File;
FSize, FPos, TempPos, tmpsize:longint;
Input: TFileInfo;
i: Integer;
File64: TGpHugeFile;

Procedure Wave(Buffer: TBuffer; BufSize: Integer);
var i: Longint;
k: Integer;
fname: String;
Begin
for i:=1 to BufSize-12 do Begin
if buffer[i]='R' then
if buffer[i+1]='I' then
if buffer[i+2]='F' then
if buffer[i+3]='F' then
if buffer[i+8]='W' then
if buffer[i+9]='A' then
if buffer[i+10]='V' then
if buffer[i+11]='E' then Begin
Inc(Count);
File64.Seek(FPos+i+3);
File64.BlockRead(FSize,4, HInstance);
FSize:=FSize+8;
fname:=ExtractFileName('data.pak');
input.Name:='';
k:=1;
repeat
input.Name:=input.Name+fname[k];
inc(k);
until (k=8)or(fname[k]='.');
input.Name:= IntToHex(FSize, 16) + '_' + IntToHex(FPos+i-1, 16) + '.wav';
input.Size:= FSize;
input.StartOffset:=FPos+i-1;
List[count]:=input;
End;
End;
End;

procedure SetFileSize(FileName: AnsiString; NewSize: Int64);
var fs: TFileStream;
begin
fs:= TFileStream.Create(FileName, fmOpenReadWrite);
fs.Size:= NewSize;
fs.Free;
end;

begin
File64:= TGpHugeFile.Create('data.pak');
File64.Reset(1);

FPos:=0;
Repeat
Application.ProcessMessages;
File64.BlockRead(Buffer, bufsize, HInstance);
TempPos:= File64.FilePos - 12;
Wave(Buffer, bufsize);
FPos:= FPos + bufsize;
File64.Seek(TempPos);
Until File64.FilePos >= File64.FileSize-bufsize;
File64.BlockRead(Buffer, File64.FileSize-File64.FilePos, HInstance);
Wave(Buffer, File64.FileSize-File64.FilePos);
File64.Truncate;
File64.Close;

Writeln(Count);
end. [/more]. Там используется специальный компонент, который умеет работать с большими файлами. Но всё равно, если подсунуть программе файл, больше 2 Gb, вылетает ошибка. Насколько я понял, это как то связано с bufsize... А вот как исправить, увы, не знаю
Автор: folta
Дата сообщения: 05.12.2012 19:38
почему стойка (Undeclared identifier: 'key') на >> key[i] := value;
что объявить для массива?

Код:
procedure TForm1.Button1Click(Sender: TObject);
var
f : TextFile;
value, i : Integer;
begin
if OpenDialog1.Execute then
begin
AssignFile(f, OpenDialog1.FileName);
Reset(f);

i := 0;
while not SeekEof(f) do
begin
Read(f, value);
Inc(i);
key[i] := value;
end;
CloseFile(f);

end;
end;
Автор: R3Pa4eK
Дата сообщения: 05.12.2012 19:46
folta
[more=Попробуйте]
procedure TForm1.Button1Click(Sender: TObject);
var
f : TextFile;
value, i : Integer;
key: Array of Char;
begin
if OpenDialog1.Execute then
begin
AssignFile(f, OpenDialog1.FileName);
Reset(f);
SetLength(key, FileSize(f));
i := 0;
while not SeekEof(f) do
begin
Read(f, value);
Inc(i);
key[i] := value;
end;
CloseFile(f);

end;
end;
[/more]
Автор: folta
Дата сообщения: 05.12.2012 20:23
R3Pa4eK
теперь ругня на ту же строчку, но иначе:
E2010 Incompatible types: 'Char' and 'Integer'
вроде все для массива целых чисел прописано.

попробовал подставить
array of array of integer вместо Array of Char:
E2010 Incompatible types: 'Dynamic array' and 'Integer'

а вроде как просто.
открыть файл и считать содержимое в массив...на бумажке просто.
Автор: R3Pa4eK
Дата сообщения: 05.12.2012 20:35
folta
А почему именно в массив? Вот Ваш код с использованием WinApi:
[more=Код]
procedure TForm1.Button1Click(Sender: TObject);
var
hF : THandle;
S : AnsiString;
Len, CntRead : Longword;
begin
if OpenDialog1.Execute then
begin

hF := CreateFile(PChar(OpenDialog1.FileName), GENERIC_READ, FILE_SHARE_READ,
nil, OPEN_EXISTING, 0, 0);
if hF = INVALID_HANDLE_VALUE then Exit;
Len := GetFileSize(hF, @Len);
SetLength(S, Len);
try
ReadFile(hF, Pointer(S)^, Len, CntRead, nil);
finally
CloseHandle(hF);
end;

end;
end;
[/more]

А если нужно перевести в массив, то используйте следующую функцию:


Код:
type
TArrayOfStrings = array of AnsiString;

function StringToArray(Text, Cut: AnsiString): TArrayOfStrings;
var
t, i, k: Integer;
begin
SetLength(Result, 0); if Cut = '' then Cut:= #1310;
repeat SetLength(Result, Length(Result) + 1); t:= 1; k:= Pos(Cut, Text);
if k > 0 then t:= Length(Cut); i:= Length(Result) - 1;
if k > 0 then begin Result[i]:= Copy(Text, 1, k - 1); Text:= Copy(Text, k + t, Length(Text)) end else begin Result[i]:=Text; SetLength(Text, 0) end;
until Length(Text) = 0;
end;

//var a: TArrayOfStrings;
//a:= StringToArray(S, #13#10);
Автор: folta
Дата сообщения: 05.12.2012 21:34
R3Pa4eK
да, спасибо. всё замечательно.

только теперь мне несладко придется)
задача такова, взять файл>вычитать цифры в массив>с помощью chart отрисовать график.
метод с которым я возился, более менее понятен был. как чего сформировано.
теперь, надо подтягивать знания по иным функциям.
ну, все что впервые видишь, кажется непостигаемым и непробиваемым))

все одно спасибо.
уж лучше расширять кругозор, чем топтаться по знакомому пяточку.
Автор: salexn1
Дата сообщения: 06.12.2012 09:38
R3Pa4eK

Код может и правильный с точки зрения работы, но
1) он не читаемый
2) не оптимальный по памяти


Код:
function StringToArray(Text, Cut: AnsiString): TArrayOfStrings;
var
t, k, count, MaxLength: Integer;
begin
count := 0;
if Cut = '' then
Cut:= #13#10;
t := Length(Cut);
MaxLength := Length(Text);
repeat
SetLength(Result, count + 1);
k:= Pos(Cut, Text);
if k > 0 then
begin
Result[count] := Copy(Text, 1, k - 1);
Text := Copy(Text, k + t, MaxLength);
end
else
begin
Result[count] := Text;
end;
inc(count);
until k = 0;
end;
Автор: folta
Дата сообщения: 06.12.2012 10:40
так)
назрел следующий вопрос. возможно смешной и некорректный.
не хотит обустраиваться в type
TArrayOfStrings = Array of AnsiString;
именно Array > "expected but @ received array"
даже с TDelim=set of Char
E2169 Field definition not allowed after methods or properties

Embarcadero RAD Studio XE Version 15.0.3953.35171
чую что собака в этом. не?!
Автор: Frodo_Torbins
Дата сообщения: 06.12.2012 12:09
folta
Вы его не туда пихаете. Внимательно посмотрите где определение класса формы заканчивается.
И кстати, почему было ”key: array of integer” не сделать?
Автор: folta
Дата сообщения: 06.12.2012 15:20
Frodo_Torbins
да, вот это само то.

я не понял, куда делся мой массив в примерах с api и TArrayOfStrings, да простят меня за дремучесть. и пока не просветлят примером или комментарием строк, хоть чужим, хоть каким. вернусь с чего начинал:

вот сейчас все замечательно, но считывая массив цифр из файла(ANSI), выдает критическую ошибку, мол доступ по адресу для записи закрыт..
обозначить размеры массива?!
но мне нужен бездонный.

Код:
procedure TForm2.RzButton2Click(Sender: TObject);
var
f : TextFile;
value, i : Integer;
begin
if OpenDialog1.Execute then
begin
AssignFile(f, OpenDialog1.FileName);
Reset(f);

i := 0;
while not SeekEof(f) do
begin
Read(f, value);
Inc(i);
key[i] := value;
end;
CloseFile(f);

end;
end;
end.
Автор: R3Pa4eK
Дата сообщения: 06.12.2012 15:45
folta
Нужно обозначить размер массива. Как то так:
[more]
procedure TForm2.RzButton2Click(Sender: TObject);
var
f : TextFile;
value, i : Integer;
begin
if OpenDialog1.Execute then
begin
AssignFile(f, OpenDialog1.FileName);
Reset(f);

SetLength(key, FileSize(f)); //Размер массива key будет равняться размеру файла

i := 0;
while not SeekEof(f) do
begin
Read(f, value);
Inc(i);
key[i] := value;
end;
CloseFile(f);

end;
end;
end.
[/more]
Автор: Frodo_Torbins
Дата сообщения: 06.12.2012 16:56
folta
Ну или увеличивать каждый раз до нужной длины: "SetLength(key, i);".
Автор: R3Pa4eK
Дата сообщения: 06.12.2012 18:07
А как добавить в файл свою информацию? Например: у меня есть файл (архив), в него нужно информацию для распаковки (offset'ы и размеры, а также упаковщик). Пока что я таскаю за собой текстовый файл, в котором записана вся информация. Но это ведь не выход...

/upd
Решено!
Автор: folta
Дата сообщения: 06.12.2012 18:58
снова я)
то чего я предполагал, случилоси.

Цитата:
invalid numeric input

при попытке добавить в массив из файла. хотя там только цифры, та же картина в уникоде.
в гугле полно на эту тему, но все мимо.
что-то надо объявить массиву...что?
а лучше универсализировать, чтобы не спотыкалось на чтении файла и выдергивало только цифры.
может сам дойду пешком..
Автор: Frodo_Torbins
Дата сообщения: 06.12.2012 21:12
folta
Не очень понятно что вы там у себя делали. Покажите лучше код.
Автор: Varenik
Дата сообщения: 06.12.2012 21:17
folta
Вам надо использовать при чтении не Read, а ReadLn
Автор: folta
Дата сообщения: 06.12.2012 22:20
вот. все простенько.
[more]unit line;

interface

uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls,
TeEngine, TeeProcs, Chart, Series, RzButton;

type
TForm2 = class(TForm)
Chart1: TChart;
Series1: TLineSeries;
Series2: TLineSeries;
RzButton1: TRzButton;
RzButton2: TRzButton;
OpenDialog1: TOpenDialog;
procedure RzButton1Click(Sender: TObject);
procedure RzButton2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.RzButton1Click(Sender: TObject);
var
i: integer;
begin
begin
Series1.Clear;

for i:= 1 to 100 do

Series1.AddXY(i, i*i, '', clBlue);
end;
end;

procedure TForm2.RzButton2Click(Sender: TObject);
var
f : TextFile;
value, i : Integer;
key: array of integer;
begin
if OpenDialog1.Execute then
begin
AssignFile(f, OpenDialog1.FileName);
Reset(f);

SetLength(key, FileSize(f));

i := 0;
while not SeekEof(f) do
begin
Read(f, value);
Inc(i);
key[i] := value;
end;
CloseFile(f);

end;
end;
end.[/more]
только с процедурой TChar еще не разобрался, так что с прорисовкой графика из массива, это на десерт)

Varenik
а ни в какую.
я и в строчку, и в столбик, никак.
все одно спасибо, понял куда копать.
Автор: alex1334
Дата сообщения: 06.12.2012 22:28
folta
invalid numeric input

У вас похоже ошибка возникает еще на этапе чтения из файла переменной integer.
Возможно проблема не в самих числах а в разделителях между числами

SetLength(key, FileSize(f));
Вероятно этот оператор совершенно неверен. Переменная key имеет тип integer то есть ее длинна 4 байта не зависимо от того какое число она хранит. А вот текстовый файл данные хранит в виде символов ASCII а это значит что число 123 занимает 3 байта а число 1234567 занимает 7 байт. Я уже не говорю про символы разделители в том числе и перевод строки и возврат каретки они тоже занимают место в файле но вообще никакого отношения к числам не имееют. Добавте еще символы разделители между числами
Автор: folta
Дата сообщения: 06.12.2012 22:47
alex1334
ммм...а я думал что Integer само отделит зерна от плевел целые.
оно то так, ваш вариант логичен.
но хотелось бы чтобы из файла извлекалось в массив и даже когда присутствуют явно некорректные символы. а не падало.
вобщем, завтра буду штудировать, как.
Автор: salexn1
Дата сообщения: 07.12.2012 07:23
folta
Для этого есть варианты:
а) обрамить все try except
б) использовать процедуру val
в) использовать ф-цию StrToIntDef

Из всего вышеперечисленного я бы выбрал val
Автор: folta
Дата сообщения: 07.12.2012 13:41
salexn1
наверное так некорректно было бы

Код:
if val = integer then ...
else ...
Автор: salexn1
Дата сообщения: 07.12.2012 14:21
folta

Цитата:

 
if val = integer then ...
else ...
 


это точно фигня...


Цитата:
 
a: single;
b: integer;
...
val(Edit1.Text,a,b);


Вы хелпом умеете пользоваться???

Автор: Frodo_Torbins
Дата сообщения: 07.12.2012 14:40
folta
А можно пример содержимого файла, а то вдруг он у вас бинарный?
Автор: folta
Дата сообщения: 07.12.2012 14:47
salexn1
что имеем:
drkb3.chm
www.delphibasics.ru.chm
если не то тыкаю, намекните.

вот хоть режьте, этот пример для моего случая непонимайн:
http://www.delphibasics.ru/Val.php

уже умолчу сколько перелистал в вебе.
да, вот такая трагедия.

Добавлено:
Frodo_Torbins
да обыкновенный.
создаю блокнотом или акелпадом.
разные. с анси и уни кодировкой.
вписываю числа. в один строчно и без пробелов, другой столбик и пробелами.
все одно.
собственно строка 123456789000
http://rghost.ru/42069015

Страницы: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374

Предыдущая тема: MPO File


Форум Ru-Board.club — поднят 15-09-2016 числа. Цель - сохранить наследие старого Ru-Board, истории становления российского интернета. Сделано для людей.