Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2005.10.09;
Скачать: [xml.tar.bz2];

Вниз

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

 
grigory ©   (2005-08-25 15:45) [0]

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


 
Poirot ©   (2005-08-25 15:55) [1]

Мда, подробнее можно!если файлы идентичны, то зачем копировать?!
или я как-то не так понял вопрос:)


 
alpet ©   (2005-08-25 15:55) [2]

А в чем проблемы?
Все вполне эффективно может быть реализовано с использованием TFileStream (или если уж хочется чистого API - c помощью File Mapping).


 
grigory ©   (2005-08-25 16:06) [3]

ну вот например есть файл 1.txt..он содержит в себе "12345"
и есть файл 2.txt..он содержит "12045"
Вот я должен проверить побайтно, и увидев что они отличаются в 3 байте, копирование не производить.
Вот мой пример.
procedure TForm1.Button1Click(Sender: TObject);
Var
 S,T   : TFileStream;
 s1,t1:char;
 i,j:integer;
Begin
S := TFileStream.Create("\\Vng\TEMP\Альпагор спорт\Логотип Альпагор\text.txt", fmOpenRead );
try
 T := TFileStream.Create("c:\Мои документы\SQL\text.txt", fmOpenWrite or fmCreate);
 try
   for i:=1 to s.size do begin
   for j:=1 to t.size do begin
     s.Read(s1,1);
     T.Read(t1,1);
     if t1<>s1 then exit
   end;
   end;
   T.CopyFrom(S, S.Size ) ;
   FileSetDate(T.Handle, FileGetDate(S.Handle));
 finally
  T.Free;
 end;
finally
 S.Free;
end;
end;

не знаю правильно ли...


 
grigory ©   (2005-08-25 16:14) [4]

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


 
OldNaum ©   (2005-08-25 16:14) [5]

вначале проверяешь идентичность файлов (hash"ем к примеру), потому принимаешь решение о дальнейшей работе. копировать или нет ) к чему такой мутор то?


 
Zeqfreed ©   (2005-08-25 16:21) [6]

Побайтное копирование + побайтное сравнение будут несколько заторможенно работать.
Как один из вариантов, можно считать контрольные суммы для файлов и сравнивать их, но для больших файлов они считаются так же достаточно долго.

Мне кажется, самым оптимальным решением будет загрузка файлов в память и их сравнение спомощью CompareMem. Или для экономии памяти можно использовать поблочное сравнение, например, блоками по 1 Кб.


 
Anatoly Podgoretsky ©   (2005-08-25 16:26) [7]

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


 
wal ©   (2005-08-25 16:26) [8]

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

С уважением.


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

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


 
Anatoly Podgoretsky ©   (2005-08-25 16:39) [10]

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


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


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


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

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2005-08-25 16:44) [12]


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


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

--
Regards, LVT.


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

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


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

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


 
Anatoly Podgoretsky ©   (2005-08-25 18:48) [15]

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


 
Zeqfreed ©   (2005-08-25 22:18) [16]

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 - не изменена

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

Description of the CompareMem function:
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. (Не точный перевод)


 
Fay ©   (2005-08-26 04:36) [17]

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

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


 
Джо ©   (2005-08-26 04:45) [18]

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


 
Defunct ©   (2005-08-26 06:24) [19]

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;


 
Defunct ©   (2005-08-26 07:02) [20]

Еще один вариант, через 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;


 
Anatoly Podgoretsky ©   (2005-08-26 12:39) [21]

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


 
Zeqfreed ©   (2005-08-26 13:59) [22]

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

Fay ©   (26.08.05 4:36) [17]


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

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


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

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


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

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


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

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

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


 
Fay ©   (2005-08-26 15:15) [23]

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


 
Anatoly Podgoretsky ©   (2005-08-26 15:42) [24]

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


 
Zeqfreed ©   (2005-08-26 17:16) [25]

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


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

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



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2005.10.09;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.013 c
14-1127126807
pazitron_brain
2005-09-19 14:46
2005.10.09
GTA : VC по сети.


11-1107914794
dmitry501
2005-02-09 05:06
2005.10.09
Архив форума


2-1125436176
SarDoX
2005-08-31 01:09
2005.10.09
Выделение в Stringgrid 2


4-1123597670
NeoMaster
2005-08-09 18:27
2005.10.09
Получение списка всех подкаталогов на всех логических дисках


14-1127306421
oldman
2005-09-21 16:40
2005.10.09
У кого стоит 1С? Проблемку поймал...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский