Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 28.06.2009, 17:34   #1
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию Скоростное копирование файлов через RAM

Такая задача: есть файл произвольного размера. Нужно поблочно копировать его в кэш заданного размера и побайтно произвести с ним некие операции и сохранить результат в новый файл. Причем размкр кэша в мб задается пользователем.
Собственно вопрос: как сделать это без загрузки ЦП и достаточно быстро?
PS. 1. TMemoryStream как кэш не катит - слишком сильная загрузка ЦП и низкая скорость.
2. Через указатели на статический массив имеет недостаток-немогу задать кэш произвольного размера в программе, только в коде.

Как быть? Подскажите, куда копать или примеры. Спасибо.
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 28.06.2009, 20:50   #2
Impuls1989
Форумчанин
 
Аватар для Impuls1989
 
Регистрация: 16.08.2008
Сообщений: 276
По умолчанию

А пробовали копировать через TFileStream? Можно копировать куда угодно (хоть в массив, хоть в переменную).
Думаю это быдет выглядеть так:
Код:
 
var Stream1, Stream2: TFileStream; 
IntBuf: array[0..9] of Integer
begin 
 if Not OpenDlg.Execute then Exit;  
  Stream1:= TFileStream.Create(OpenDlg.FileName, fmOpenRead); 
  Stream1.ReadBuffer(IntBuf, SizeOf(IntBuf)); 
  Stream2 := TFileStream.Create('TextFile.tmp', fmOpenWrite);  
  Stream2.Seek(0, soFromEnd); 
  Stream2.WriteBuffer(IntBuf, SizeOf(IntBuf)); 
  Stream2.Free; 
  Stream1.Free;
end;
Искусственный интеллект - фигня по сравнению с естественной глупостью
Impuls1989 вне форума Ответить с цитированием
Старый 28.06.2009, 21:58   #3
Ntlegend
Форумчанин
 
Аватар для Ntlegend
 
Регистрация: 12.05.2007
Сообщений: 373
По умолчанию

можна воспользоваться апишными функцыями:
CreateFile - получение доступа к файлу на чтение/запись
SetFilePointer - установить курсор на позицыю ... от начала файла
ReadFile - прочитать блок данных с файла в буфер
WritwFile - записать блок даных с буфера в файл
CloseHandle - закрыть обращение к файлу

этими функцыями с файлом можна делать все шо угодно..
Перемен! - требуют наши сердца. Перемен! - требуют наши глаза.
В нашем смехе и в наших слезах, И в пульсации вен:
"Перемен!Мы ждем перемен!"
Ntlegend вне форума Ответить с цитированием
Старый 29.06.2009, 07:51   #4
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Нет, вы немного не поняли.
Impuls1989, ваш код я уже проверял до создания этой темы-он медленный! Файл копируется вдвое медленне, чем средствами винды!
Как выход: можно создать тип массива байтов длиной от 64 мб (это кэш), в варе переменную-указатель на этот тип, затем при копировании выделять память под него, заполнять кусками по 64 мб, производить операции и записывать в результирующий файл. Только при кэше от 64 мб скорость такого копирования совпадает с виндовской!
Собсно дилема: алгоритм то хорош, но нельзя регулировать размер кэша программно, только в коде перед компиляцией, и при малых размерах кэша (менее 64 мб) он не эффективен (медленнее винды)!
Код:
Код:
...
type
  cache64mb=array[1..67108864] of Byte;
...
var
  tm_start,tm_end:TTime;  
  fl_start,fl_end:^TFileStream;
  c64mb:^cache64mb;
...
procedure TForm1.btn_sourceClick(Sender: TObject);
begin
  if od_source.Execute then
  ed_source.Text:=ExtractFileName(od_source.FileName);
end;

procedure TForm1.btn_resultClick(Sender: TObject);
begin
  if sd_result.Execute then
  ed_result.Text:=ExtractFileName(sd_result.FileName);
end;

procedure TForm1.btn_cacheClick(Sender: TObject);
var
  i,divsize,modsize:Integer;
begin
  TestMode:=btn_cache.Caption;
  lb_cache.Caption:='...';
  Application.ProcessMessages;
  New(fl_start);
  New(fl_end);
  fl_start^:=TFileStream.Create(od_source.FileName,fmShareDenyWrite);
  fl_end^:=TFileStream.Create(sd_result.FileName,fmCreate);
  New(c64mb);
  divsize:=fl_start^.Size div high(c64mb^);
  modsize:=fl_start^.Size mod high(c64mb^);
  tm_start:=Time;
  for i:=1 to divsize do
  begin
    fl_start^.Read(c64mb^,high(c64mb^));
    fl_end^.Write(c64mb^,high(c64mb^));
  end;
  fl_start^.Read(c64mb^,modsize);
  fl_end^.Write(c64mb^,modsize);
  tm_end:=Time;
  fl_start^.Free;
  fl_end^.Free;
  Dispose(fl_start);
  Dispose(fl_end);
  Dispose(c64mb);
  c64mb:=nil;
  lb_cache.Caption:=TimeToStr(tm_end-tm_start);
end;
...
Как его модифицировать, чтобы кэш можно было регулировать взависимости от длины файла и от установленного пользователем кэша в опциях проги?
Или я туплю и есть варианты проще?
Ни у кого не было схожей задачи?
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 29.06.2009, 11:47   #5
Ntlegend
Форумчанин
 
Аватар для Ntlegend
 
Регистрация: 12.05.2007
Сообщений: 373
По умолчанию

попробуй такое

Код:
var FNs, FNr:string; // пути к файлам

...
procedure TForm1.btn_sourceClick(Sender: TObject);
begin
  if not od_source.Execute then exit;
  ed_source.Text:=ExtractFileName(od_source.FileName);
 FNs:=od_source.FileName;
end;

procedure TForm1.btn_resultClick(Sender: TObject);
begin
  if not sd_result.Execute then exit;
  ed_result.Text:=ExtractFileName(sd_result.FileName);
  FNr:=sd_result.FileName;
end;

procedure TForm1.btn_cacheClick(Sender: TObject);
var
  Fs, //файл источник
  Fr,  //файл приёмник
  br,  //переменная в которой будет храниться число прочитаных бит
  sz, //размер буфера копирования
  t: cardinal;//переменная для отщиывания времени копирования
  byf:array of byte;
begin
  TestMode:=btn_cache.Caption;
  lb_cache.Caption:='...';
  Application.ProcessMessages;

  t:=GetTickCount;

  sz:=64*1024; //определяем размер буфера 64 кб
  Fs:=CreateFile(PChar(FNs),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING, 0,0);//открываем для чтения
  Fr:=CreateFile(PChar(FNr),GENERIC_WRITE,FILE_SHARE_WRITE,nil,CREATE_ALWAYS, 128,0); //открываем для записи.. если файла нету - создаем его
  SetLength(byf, sz);//устанавливаем размер буфера
  
  br:=$FFFFFFFF;
  while br>=sz do begin
   ReadFile(Fs, byf[0], sz, br, nil);  //читаем из файла в буфер
   WriteFile(Fr, byf[0], br, br, nil); // пишем из буфера в файл 
  end;  
  CloseHandle(Fs); //закрываем доступ к файлу
  CloseHandle(Fr);

  lb_cache.Caption:=IntToStr((GetTickCount - t) div 1000)+' секунд'; // выводим время
end;
Перемен! - требуют наши сердца. Перемен! - требуют наши глаза.
В нашем смехе и в наших слезах, И в пульсации вен:
"Перемен!Мы ждем перемен!"
Ntlegend вне форума Ответить с цитированием
Старый 02.07.2009, 07:29   #6
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Ntlegend, спасибо! Действительно эта апишная функция эффективнее! И проц несильно грузит.
Только мне не понятен 1 момент:
Код:
br:=$FFFFFFFF;
  while br>=sz do begin
   ReadFile(Fs, byf[0], sz, br, nil);  //читаем из файла в буфер
   WriteFile(Fr, byf[0], br, br, nil); // пишем из буфера в файл 
  end;
Как я понимаю, ты в переменную br заносишь наибольшее значение по ее типу, а в цикле как понять это условие? Или это специально для бесконечного цикла, чтобы копировалось кусками пока не конец исходного файла?
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 02.07.2009, 08:24   #7
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

3D Hunter, да. Вы всё правильно поняли.

Вот только я бы рекомендовал переписать кусок, воспользовавшись примером из старого доброго TP:
Код:
repeat
  BlockRead(FromF, Buf, SizeOf(Buf), NumRead);
  BlockWrite(ToF, Buf, NumRead, NumWritten);
until (NumRead = 0) or (NumWritten <> NumRead);
Serge_Bliznykov вне форума Ответить с цитированием
Старый 03.07.2009, 10:02   #8
3D Hunter
Сумрачная тень
Форумчанин
 
Аватар для 3D Hunter
 
Регистрация: 05.03.2009
Сообщений: 689
По умолчанию

Serge_Bliznykov, аргументируйте, пожалуйста, чем лучше процедуры чтения записи нетипизтрованного файла апишных? В своей тестовой проге я пробовал и такой вариант с нетипизтрованными файлами. И тоже медленно, не лучше медленных потоков.
Кстати, если файл открыт с помощью апишной функции CreateFile, то этот хэндл можно использовать в виде параметра в BlockRead/BlockWrite?
"ковыряю изнутри" (с)
3D Hunter вне форума Ответить с цитированием
Старый 03.07.2009, 14:21   #9
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

3D Hunter, вот только не надо мне приписывать то, что я не говорил... я сказал, что вместо цикла:
Код:
  br:=$FFFFFFFF;
  while br>=sz do begin
лучше использовать цикл
repeat ... until (...);
ВСЁ. и ничего больше.

теперь 2) уже давно я заметил, что на современных мамках (процессорах) + Windows в файловом менеджере FAR крайне желательно в настройках ставить опцию "использовать системную функцию копирования". Это приводит к резкому (иногда в разы) увеличению скорости копирования. я не буду утверждать 100% (не видя, на что это опция влияет внутри самого фара и как там реализовано копирование), но рискну предположить, что в случае этой опции копирование идёт как раз через APIшные функции, что, как показывает данный пример, гораздо эффективнее чтения/записи блоками...

Цитата:
если файл открыт с помощью апишной функции CreateFile, то этот хэндл можно использовать в виде параметра в BlockRead/BlockWrite
по моему, НЕТ, нельзя!
Serge_Bliznykov вне форума Ответить с цитированием
Старый 03.07.2009, 19:41   #10
Somebody
Участник клуба
 
Регистрация: 08.10.2007
Сообщений: 1,185
По умолчанию

Если читается большими блоками, может быть, в CreateFile отключить системное кеширование? Думаю (но не проверял), что быстрее должно стать. А то, что в TotalCommander'е с включенным "режимом совместимости" (help говорит, что это CopyFileEx) часто быстрее копируется, тоже заметил. Интересно, как CopyFileEx работает тогда...
Somebody вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
копирование файлов 59inferno Общие вопросы C/C++ 4 16.06.2009 15:59
Связь с кучей dbf файлов (таблиц) через OLEDB через UNION ALL Sasha811 SQL, базы данных 0 01.01.2009 14:04
Копирование файлов через http протокол Serega_P Работа с сетью в Delphi 3 06.12.2008 14:35
Temp INI in RAM Altera Общие вопросы Delphi 5 17.02.2008 07:25