Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Побайтное копирование файла!


Страницы:   1 2

grigory ©   (2005-08-25 15:45:00) 

Нужно произвести корректное копирование, то есть по байтно. : Если файлы полностью идэнтичны и совпали, то можно копировать..а если хоть один символ отличается, то нет! Для примера файл текстовый.
стандартная апи-функция CopyFile заменяет файл, затирая все предыдущее. Жду помощи. Спасибо.


Fay   (2005-08-26 17:38:00) [1]

2 Zeqfreed ©   (26.08.05 17:16) [25]
Пиши на API. Он прозрачнее, справка великолепная.


Zeqfreed   (2005-08-26 17:16:00) [2]

Fay ©   (26.08.05 15:15) [23]
Ok, спасибо, буду знать :)
Просто в справке из раздела о FileOpen как-то не нашлась она и в списке File management routines нет её..


Anatoly Podgoretsky   (2005-08-26 15:42:00) [3]

Zeqfreed ©   (26.08.05 13:59) [22]
Оно удовлетворяет, оно просто медленное и скорость пропорциональна размеру файла. Всю ветку нитью не надо копировать идентичные файлы, если только для того, что бы изменить дату, вот ее милую и надо менять.


Fay   (2005-08-26 15:15:00) [4]

2 Zeqfreed ©   (26.08.05 13:59) [22]
>> Если честно, то не нашёл ф-ций которые бы возвращали размер файла по его дескриптору
GetFileSize(Ex)
8)


Zeqfreed   (2005-08-26 13:59:00) [5]

Anatoly Podgoretsky ©   (26.08.05 12:39) [21]
Ну почему же идиотское? Разве оно не удовлетворяет условию задачи "изменить дату одного из файлов, если два файла идентичны"?

Fay ©   (26.08.05 4:36) [17]


>2 All
> Задача совершенно идиотская. Полностью согласен с
> Анатолием.

ИМХО, задача просто врядли нужная на практике, но мало ли для чего это может потребоваться.


> Про try..finally слышали?

Слышал. Ещё не вошло в привычку использовать, видимо.


> Зачем выделять память сразу под 2 файла полностью?

Под два чтобы сравнить. Полностью - как один из вариантов. Согласен, что для более-менее больших файлов лучше использовать блочное сравнение, о чем я говорил в [6].


> Зачем FindFirst, когда файлы уже открыты?

Если честно, то не нашёл ф-ций которые бы возвращали размер файла по его дескриптору, полученному ф-цией FileOpen или аналогичными. А FileOpen использовал чтобы изменить дату файла так как это было показано в примере автора ветки.

Чем-то ещё не угодил? =)


Anatoly Podgoretsky   (2005-08-26 12:39:00) [6]

Zeqfreed ©   (25.08.05 22:18) [16]
Идиотское решение, всего то надо изменить дату у файла.


Defunct   (2005-08-26 07:02:00) [7]

Еще один вариант, через FileStream. Этот вариант мне нравится больше.

function SameFilesFS( File1, File2: String; CallBackWnd : hwnd = 0 ):boolean;
const
 optBufSize = 1024*1024 div 4;
type
 PBuffer = ^TBuffer;
 TBuffer = array[0..optBufSize-1] of Cardinal;
 PByteBuffer = ^TByteBuffer;
 TByteBuffer = array[0..optBufSize*4 - 1] of byte;
var
 F1, F2 : TFileStream;
 BlockSize : Integer;
 Buf1, Buf2 : PBuffer;
 i : integer;
 Cnt : Integer;
begin
  Result := False;

  if not FileExists( File1 ) or
     not FileExists( File2 ) then
     raise EFilerError.Create('File not found');

  New(Buf1);
  F1 := TFileStream.Create( File1, fmOpenRead or fmShareDenyNone );
  try
     New(Buf2);
     F2 := TFileStream.Create( File2, fmOpenRead or fmShareDenyNone );
     try
        if F1.Size <> F2.Size then exit;

        if F1.Size <> 0 then
           BlockSize := optBufSize * 4
        else
           BlockSize := 0;
        F1.Position := 0;
        F2.Position := 0;
        Cnt := 0;

        while (BlockSize > 0) do
        begin
           BlockSize := F1.Read( Buf1^, BlockSize );
           BlockSize := F2.Read( Buf2^, BlockSize );

           if BlockSize mod 4 <> 0 then
              for i := BlockSize to BlockSize + (4-BlockSize mod 4) do
                 begin
                    PByteBuffer( Buf1 )[i] := 0;
                    PByteBuffer( Buf2 )[i] := 0;
                 end;

           for i := 0 to (BlockSize div 4) do
               if Buf1[i] <> Buf2[i] then exit;
           inc(Cnt);

           if callbackwnd <> 0 then
              SetWindowText( callbackwnd, PChar( IntToStr( Cnt ) + ' mb compared' ) );
        end;
        Result := True
     finally
        F2.Free;
        Dispose( Buf2 )
     end
  finally
     F1.Free;
     Dispose( Buf1 )
  end
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
 if SameFilesFS('с:\1.avi', 'с:\2.avi', Handle ) then
    ShowMessage('Файлы совпадают' )
 else
    ShowMessage('Файлы не совпадают');
end;


Defunct   (2005-08-26 06:24:00) [8]

grigory ©   (25.08.05 17:34) [14]
> а именно в сравнении, с целью потом принять дальнейшее решение..результат сравнения true - файлы одинаковы, false - файлы различаются хотя бы на байт.


Написал вам параноидальную функцию. Играйтесь, хотя задача и правда немного того..

function SameFiles( File1, File2: String ):boolean;
const
 optBufSize = 1024*1024 div 4;
type
 PBuffer = ^TBuffer;
 TBuffer = array[0..optBufSize-1] of Cardinal;
 PByteBuffer = ^TByteBuffer;
 TByteBuffer = array[0..optBufSize*4 - 1] of byte;
var
 F1, F2 : File;
 BlockSize : Integer;
 Buf1, Buf2 : PBuffer;
 i : integer;
begin
  Result := False;

  if not FileExists( File1 ) or
     not FileExists( File2 ) then
     raise EFilerError.Create('File not found');

  AssignFile( F1, File1 );
  AssignFile( F2, File2 );
  Reset( F1, 1);
  try
     Reset( F2, 1);
     try
        if FileSize( F1 ) <> FileSize( F2 ) then exit;

        BlockSize := optBufSize * 4;
        New(Buf1);
        try
           New( Buf2 );
           try

              while (not Result) and (BlockSize > 0) and (not Eof(F1)) do
              begin
                 BlockRead( F1, Buf1^, BlockSize, BlockSize );
                 BlockRead( F2, Buf2^, BlockSize, BlockSize );

                 if BlockSize mod 4 <> 0 then
                    for i := BlockSize to BlockSize + (4-BlockSize mod 4) do
                       begin
                          PByteBuffer( Buf1 )[i] := 0;
                          PByteBuffer( Buf2 )[i] := 0;
                       end;

                 for i := 0 to (BlockSize div 4) do
                    if Buf1[i] <> Buf2[i] then exit;

              end;
              Result := True;
           finally
              Dispose( Buf2 );
           end
        finally
           Dispose( Buf1 );
        end
     finally
        CloseFile( F2 );
     end
  finally
     CloseFile( F1 );
  end

end;

procedure TForm1.Button4Click(Sender: TObject);
begin
 if SameFiles('c:\1.avi', 'c:\2.avi' ) then
    ShowMessage('Файлы совпадают' )
 else
    ShowMessage('Файлы не совпадают');
end;


Джо   (2005-08-26 04:45:00) [9]

Скопируйте один файл и другой мы дадим вам бесплатно.


Fay   (2005-08-26 04:36:00) [10]

2 All
Задача совершенно идиотская. Полностью согласен с Анатолием.

2 Zeqfreed ©   (25.08.05 22:18) [16]
Зачем FindFirst, когда файлы уже открыты?
Зачем выделять память сразу под 2 файла полностью?
Про try..finally слышали?


Zeqfreed   (2005-08-25 22:18:00) [11]

grigory ©   (25.08.05 17:34) [14]

function ChangeFileDate(const Src, Dst : String) : boolean;
var
fSrc, fDst : Integer;
SrcSize, DstSize, SrcRead, DstRead : Integer;
sr : TSearchRec;
memSrc, memDst : Pointer;
begin
Result := false;

//Открываем и получаем дескрипторы нужных файлов
fSrc := FileOpen(Src, fmOpenRead);
fDst := FileOpen(Dst, fmOpenReadWrite);
if (fSrc = -1) or (fDst = -1) then Exit;

//Узнаем размер файла-источника
FindFirst(Src, faAnyFile, sr);
 SrcSize := sr.Size;
FindClose(sr);

//Узнаем размер файла-приемника
FindFirst(Dst, faAnyFile, sr);
 DstSize := sr.Size;
FindClose(sr);

//Если размер файлов одинаковый проверяем дальше
if (SrcSize = DstSize) then begin
 //Выделяем в памяти место для хранения 2-х фалов
 GetMem(memSrc, SrcSize);
 GetMem(memDst, DstSize);

 //Считываем в выделенную память оба файла
 SrcRead := FileRead(fSrc, memSrc^, SrcSize);
 DstRead := FileRead(fDst, memDst^, DstSize);

 //Если считывание прошло корректно и файлы одинаковы
 if ((SrcSize = SrcRead) and (DstSize = DstRead)) and   CompareMem(memSrc, memDst, SrcSize) then begin
  //Изменяем дату
  Result := (FileSetDate(fDst, FileGetDate(fSrc)) = 0);
 end;

 //Освобождаем выделенное место
 FreeMem(memDst);
 FreeMem(memSrc);
end;

//Закрываем файлы
FileClose(fDst);
FileClose(fSrc);
end;


Src (файл-источник) - файл, дата которого копируется
Dst (файл-приемник) - файл, дата которого изменяется
Возвращаемые значения: true - дата изменена; false - не изменена

Ф-ция сравнивает два файла, если их сожержимое идентично, устанавливает для файла-приемника дату файла-источника.

Descriptionof the CompareMemfunction:
CompareMem performs a binary compare of Length bytes of memory referenced by P1 to that of P2.  CompareMem returns True if the memory referenced by P1 is identical to that of P2. (Delphi Help)

Описаниеф-ции CompareMem:
Ф-ция CompareMem осуществляет бинарное сравнение [Length] байт памяти, начинающихся с позиций переданных через указатели P1 и P2. Ф-ция CompareMem возвращает true, если участок памяти, начинающийся с позиции P1, идентичен участку, начинающемуся с позиции P2. (Не точный перевод)


Anatoly Podgoretsky   (2005-08-25 18:48:00) [12]

Leonid Troyanovsky ©   (25.08.05 16:44) [12]
Не важно где, ты скажи зачем копировать файл, если они идентины?


grigory   (2005-08-25 17:34:00) [13]

Хорошо, пусть дело не в копировании, а именно в сравнении, с целью потом принять дальнейшее решение..результат сравнения true - файлы одинаковы, false - файлы различаются хотя бы на байт.
Моим способом не катит, ну очень долго..к тому же это как бы посимвольно..обыкновенным чтением.
а вот что такое CompareMem я не знаю к сожалению:(( по крайней мере сразу не пойму о чем это..если можно сказать, или пример такого варианта с этой функцией.
Спасибо заранее.


grigory   (2005-08-25 17:25:00) [14]

че то не понял я ничего:) если моим способом, то все делается, но ужасно долго..минут 5 10 кб файл((((


Leonid Troyanovsky   (2005-08-25 16:44:00) [15]


> Anatoly Podgoretsky ©   (25.08.05 16:39) [10]
> Вот процедура, которая выполняет задуманное
> procedure TForm1.Button1Click(Sender: TObject);
> Begin
> end;


Ну, тут все файлы могут находится в разных
местах, скажем, в интранет.

--
Regards, LVT.


Leonid Troyanovsky   (2005-08-25 16:42:00) [16]


> OldNaum ©   (25.08.05 16:14) [5]
> вначале проверяешь идентичность файлов (hash'ем к примеру),


Никакой хеш тут не спасет.
Т.е., открываем два файла на чтение, третий на запись.
считываем из первого и второго в буфер,
сравниваем буферы (CompareMem etc),
если все в порядке, копируем буфер в третий,
при нахождении отличий закрываем все и удаляем третий.

--
Regards, LVT.


Anatoly Podgoretsky   (2005-08-25 16:39:00) [17]

Вот процедура, которая выполняет задуманное
procedure TForm1.Button1Click(Sender: TObject);
Begin
end;


alex_***   (2005-08-25 16:36:00) [18]

может сравнить файлы - CRC снять? Быстрее будет, я думаю. И потом копировать одной командой


wal   (2005-08-25 16:26:00) [19]

Хм. Если я првильно понял задание то:
1. Если файлы не идентичны, то копировать не нужно.
2. Если файлы идентичны, то копирование не имеет смысла.
Вывод: плюнь и не копируй никогда. Или ключевая строчка эта: FileSetDate...?

С уважением.


Anatoly Podgoretsky   (2005-08-25 16:26:00) [20]

grigory ©   (25.08.05 15:45)  
Зачем заменять одно идентичное содержимое другим идентичным?
Я бы понял если наоборот, а так какая то бессмыслица.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо