2009-06-11 2 views
1

Кто-нибудь знает, как выгрузить файл из кеша? Я пишу файл на диск, а затем хочу его прочитать. Однако Windows дает мне файл из кеша.Как выгрузить файл из кеша?

begin 
... 

{-- Write file --} 
AssignFile(F, FileName); 
Rewrite(F, 1); 
BlockWrite(F, Buf[0], Chunk); 
CloseFile(F);    { FLUSH } 

some code... 
then..... 

{-- Read file --} 
AssignFile(F, FileName); 
Reset(F, 1);                
BlockRead(F, Buf[0], Chunk);  <----------- getting file from cache 
CloseFile(F); 
end; 

- Я пытаюсь определить записи/скорость чтения диска.

+0

вы пытаетесь определить, сколько времени потребуется, чтобы прочитать кусок?Если это так, возможно, нет простого способа предотвратить чтение из кеша, поскольку это ОС и, возможно, аппаратное обеспечение (если у диска есть внутренний кеш). –

+0

@Gerry - Да, это то, что я пытаюсь сделать. Я думаю, что (физический) дисковый кэш можно легко разбить, если я прочитаю в нем некоторые другие файлы. Так что это не должно быть проблемой. – Ampere

ответ

4

Некоторые код, чтобы продемонстрировать использование FILE_FLAG_NO_BUFFERING и проверить, как это влияет на время чтения:

uses 
    MMSystem; 

function GetTimeForRead(ABuffered: boolean): single; 
const 
    FileToRead = // name of file with maybe 500 MByte size 
var 
    FlagsAndAttributes: DWORD; 
    FileHandle: THandle; 
    SrcStream, DestStream: TStream; 
    Ticks: DWord; 
begin 
    if ABuffered then 
    FlagsAndAttributes := FILE_ATTRIBUTE_NORMAL 
    else 
    FlagsAndAttributes := FILE_FLAG_NO_BUFFERING; 
    FileHandle := CreateFile(FileToRead, GENERIC_READ, FILE_SHARE_READ, nil, 
    OPEN_EXISTING, FlagsAndAttributes, 0); 
    if FileHandle = INVALID_HANDLE_VALUE then begin 
    Result := 0.0; 
    exit; 
    end; 

    SrcStream := THandleStream.Create(FileHandle); 
    try 
    DestStream := TMemoryStream.Create; 
    try 
     DestStream.Size := SrcStream.Size; 

     Sleep(0); 
     Ticks := timeGetTime; 
     DestStream.CopyFrom(SrcStream, SrcStream.Size); 
     Result := 0.001 * (timeGetTime - Ticks); 

    finally 
     DestStream.Free; 
    end; 
    finally 
    SrcStream.Free; 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    i: integer; 
begin 
    Button1.Enabled := FALSE; 
    try 
    Update; 
    Memo1.Lines.Clear; 
    for i := 1 to 5 do begin 
     Memo1.Lines.Add(Format('Time for buffered file read: %.3f s', 
     [GetTimeForRead(TRUE)])); 
    end; 
    for i := 1 to 5 do begin 
     Memo1.Lines.Add(Format('Time for unbuffered file read: %.3f s', 
     [GetTimeForRead(FALSE)])); 
    end; 
    finally 
    Button1.Enabled := TRUE; 
    end; 
end; 

Запуск этого кода с файлом 420 размера МБайт дает на моей системе:

Время для буферизованного файла: 3,974 с
Время для буферизованного файла: 0,922 с
Время считывания буферного файла: 0,937 с
Время для буферизации красное чтение файла: 0,937 сек
Времени буферного чтения файла: 0,938 сек
Времени для небуферизован чтения файла: 3,922 сек
Времени для небуферизован чтения файла: 4000 сек
Времени для небуферизован чтения файла: 4,016 сек
Времени для небуферизован чтения файла: 4,062 сек
Время небуферизованном чтения файла: 3985 s

+0

СПАСИБО mghie! Я думаю, что это тот ответ, в котором я нуждаюсь. Спасибо большое! – Ampere

+1

Почему вы вызываете Sleep (0) в свой код? – Ampere

+0

Ну, его можно также удалить. Это не имеет особого значения для кода, для выполнения которого требуется несколько секунд, но когда у меня есть код, который я хочу быстро найти (не используя внешний профилировщик, а только блок профилирования, который я использую), я обычно вставляю «Сон (0); " прямо перед запуском, чтобы выполнить код, который должен быть профилирован в течение всего временного фрагмента. Это определенно важно, если вы хотите сравнить время выполнения нескольких последовательных фрагментов кода, каждый из которых занимает несколько миллисекунд. – mghie

4

Я думаю, что вы неправильно поняли концепцию промывки файла.

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

(поток автоматически покраснел при закрытии. Открытие файла и смыв без написания ничего к нему не имеет никакого эффекта, что так всегда.)

Вы можете посмотреть в FILE_FLAG_NO_BUFFERING флаг для чтения файла, но из документации видно, что он не влияет на файлы на жестком диске.

MSDN: CreateFile

+0

Флаг также имеет эффект для файлов на жестком диске, но он не может отключить буферизацию самого диска. Этот кэш обычно находится в диапазоне от 2 до 32 мегабайт на современном диске, поэтому чем больше размер файла, тем меньше будет влияние кэша накопителя. – mghie

+0

Размер файла не менее 100 МБ. Поэтому я полагаю, что Windows кэширует даже огромные файлы. – Ampere

+0

Я думаю, что (физический) дисковый кэш можно легко разбить, если я прочитаю в нем некоторые другие файлы. Так что это не должно быть проблемой. – Ampere

2

кэширование файлов является операцией уровня ОС, поэтому не зависит от того, используете вы Delphi или любой другой язык.

Если вы дадите нам некоторое представление об , почему вы хотите, чтобы вы не читали кеш, вам может быть проще помочь.

+0

Некоторые люди (mghie) уже выяснили, почему я хочу это сделать :) – Ampere

0

Код должен быть точным, если вы не используете недопустимые значения для переменной Chunk. Например, если chunk = 0, то он не будет считывать какие-либо данные в буфер, поэтому буфер сохранит старое значение. (Которые могут быть теми же данными, которые вы только что записали на диск.)

+0

№ Chunk составляет около 100 МБ. – Ampere

4

Вам нужно будет использовать API Win32 напрямую, в частности CreateFile с флагом FILE_FLAG_NO_BUFFERING. Это заставляет ОС читать с диска вместо кеша и имеет побочный эффект, что он также очищает кеш для этого файла, поэтому следующее чтение без флага также попадает на диск, хотя оно читает его в кеш тогда.

Смежные вопросы