Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Delphi Datei physikalisch lesen/schreiben ohne den Windows-Cache (https://www.delphipraxis.net/103342-datei-physikalisch-lesen-schreiben-ohne-den-windows-cache.html)

devidespe 14. Nov 2007 16:12


Datei physikalisch lesen/schreiben ohne den Windows-Cache
 
Hallo,

ich muss auf einem USB-Stick eine Datei erstellen, ihren Inhalt lesen und anschließend miteinander vergleichen. Das habe ich bisher mit normalen Delphi-Funktionen realisiert (Assign, Rewrite, Write, Read, Close). Die Sache hat nur einen Haken: den Windows-Cache. Beim Schreiben auf den USB-Stick meldet mir Windows schneller, dass die Datei geschrieben wurde, als es tatsächlich der Fall ist. Somit kann ich nicht den Zeitpunkt ermitteln, bei dem ich mit dem Lesen beginnen kann.

Um dieses Problem zu umgehen, habe ich gehört, man kann das entsprechende Medium physikalisch öffnen und somit am Windows-Cache "vorbeischreiben".

Bisher habe ich physikalische Laufwerke immer so geöffnet:

Delphi-Quellcode:
Handle := CreateFile(PChar('\\.\PhysicalDrive1'),
                       0,
                       FILE_SHARE_READ or FILE_SHARE_WRITE,
                       nil,
                       OPEN_EXISTING,
                       0,
                       0);
und so

Delphi-Quellcode:
CloseHandle(Handle);
wieder geschlossen.

Nun ist mir allerdings schleierhaft, wie ich nach dem Öffnen eine Datei schreiben soll. Es gibt zwar die WriteFile- und ReadFile-Funktionen, die nach dem Aufruf von CreateFile zum Einsatz kommen, aber wie soll ich da eine Datei angeben, die zuvor auch noch erstellt werden muss ?

taaktaak 14. Nov 2007 16:16

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Moin, Moin,
wie wäre es, wenn du statt OPEN_EXISTING mal CREATE_NEW verwendest (F1 auf CreateFile öffnet die recht gute Hilfe) ...
Gruß Ralph :bounce1:

shmia 14. Nov 2007 16:32

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Zitat:

Zitat von devidespe
Um dieses Problem zu umgehen, habe ich gehört, man kann das entsprechende Medium physikalisch öffnen und somit am Windows-Cache "vorbeischreiben".

Das wäre extrem aufwändig, da du so das Dateisystem (FAT16, FAT32, NTFS) selbst unterstützen müsstest.
Lösung: einen Stream verwenden.
Man kann aber nicht direkt einen TFileStream verwenden, sondern muss auf THandleStream ausweichen.
Nur so kann man FILE_FLAG_WRITE_THROUGH angeben.
Delphi-Quellcode:
function CreateUnbuffedFilestream(const filename:string):TStream;
var
   fhandle : THandle;
begin
   fhandle := CreateFile(PChar(filename), GENERIC_READ or GENERIC_WRITE,
   0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_WRITE_THROUGH, 0);

   if hnd <> INVALID_HANDLE_VALUE then
     result := THandleStream.Create(fhandle)
   else
     result := nil;
end;

Chewie 14. Nov 2007 17:08

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Mal ne vielleicht doofe Frage:

Wenn ich eine Datei schreibe und die sofort danach wieder lesen will, kann es mir dann aus meiner (Anwender-)Sicht nicht egal sein, ob Caches verwendet werden oder nicht? Caches (zumindest die Schreibcaches bei Datenträgern) sollten transparent sein, es ist (in diesem Fall) Sache des Betriebssystems bzw. der Treiber, dafür zu sorgen.
Wenn ich also eine Datei schreibe und diese dann nicht sofort lesen kann, so ist das meiner Meinung nach ein Mangel des Betriebssystems, der behoben werden sollte.

Oder versteh ich da was falsch?

mkinzler 14. Nov 2007 17:11

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Ich glaub sein Problem ist, das Windows Erfolf meldet, die daten aber noch nicht zurückgeschrieben wurden. wenn man nun den Stick abzieht, hat man Müll!

Chewie 14. Nov 2007 17:16

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Ach so! Gut, das wäre eine Erklärung.

Dann würde ich aber sagen, er sollte lieber prüfen, ob der Stick abgezogen werden kann oder nicht. Dafür ist ja das Dienstprogramm von Windows da, das sich in der Systray einnistet. Wenn man die gleiche Prüfung, die in diesem Programm vorkommt, anwendet, sollte das gewünschte erreicht sein. Bleibt natürlich die Frage, welche das genau ist ;-)

Ich finds eben unsauber, ganz auf den Schreibcache zu verzichten. Wenn der Administrator des Systems den Schreibcache anschaltet, dann wird er sich was dabei denken und fände es nicht schön, wenn jedes Programm diese Einstellung ignoriert und durchschreibt. Dann kann er den Cache auch gleich deaktivieren.


Das soll jetzt keine generelle Kritik an der Vorangehensweise sein, ich weiß ja nicht, was das Programm konkret machen soll. Aber prinzipiell finde ich, man sollte zunächst mal versuchen, mit der Konfiguration des Betriebssystem zurechtzukommen, als diese umgehen zu wollen.

Muetze1 14. Nov 2007 17:20

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Dieses Fehlverhalten bei Wechseldatenträgern hatte Windows nur bei 2000. Bei XP ist der Schreibcache bei Wechseldatenträgern standardmässig deaktiviert. Grundlegend weiss man aber trotzdem nicht, wann er mit dem Schreiben fertig ist, so lange man nicht mit der WebCam die LED des Sticks beobachtet :zwinker:

devidespe 14. Nov 2007 17:48

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Vielleicht war die gewünschte Aufgabe meiner Anwendung falsch umschrieben.

Eine Teilapplikation soll bspw. die Lesegeschwindigkeit der USB-Medien und auch einer zuvor gebrannten CD ermitteln. Dafür wird die Testdatei eingelesen und die Zeit ermittelt, die dafür benötigt wird. Nehmen wir einmal an, dieser Vorgang dauert für eine 16 MByte Datei 5 Sekunden. Beim zweiten Einlesevorgang nimmt Windows die Datei aber aus seinem Datei-Cache und ich erhalte eine Lesezeit von 0,01 Sekunden - das verfälscht mein Ergebnis auf unerwünschte Art und Weise.

Wenn die CreateFile-Methode bedeutet, dass ich mich mit Dateisystemen und Sektoren rumschlagen muss, ist die Sache den Aufwand nicht Wert.

Mir ist auch keine Windows API-Funktion bekannt, um den Dateisystemcache für bestimmte Laufwerke abzuschalten (was allerdings ohne Neustart erfolgen müsste).

@shmia: Deinen Vorschlag mit dem Stream muss ich ausprobieren, er klingt auch recht vielversprechend. Info folgt dann hier in dieser Diskussion.

devidespe 14. Apr 2010 16:36

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Zitat:

Zitat von shmia
Das wäre extrem aufwändig, da du so das Dateisystem (FAT16, FAT32, NTFS) selbst unterstützen müsstest.
Lösung: einen Stream verwenden.
Man kann aber nicht direkt einen TFileStream verwenden, sondern muss auf THandleStream ausweichen.
Nur so kann man FILE_FLAG_WRITE_THROUGH angeben.
Delphi-Quellcode:
function CreateUnbuffedFilestream(const filename:string):TStream;
var
   fhandle : THandle;
begin
   fhandle := CreateFile(PChar(filename), GENERIC_READ or GENERIC_WRITE,
   0, nil, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_WRITE_THROUGH, 0);

   if hnd <> INVALID_HANDLE_VALUE then
     result := THandleStream.Create(fhandle)
   else
     result := nil;
end;

Hallo shmia,

ich muss nochmal auf Deinen oben genannten Code zurückkommen. Zuerst einmal funktioniert er. Ist es aber möglich, dass das Beschreiben mit FILE_FLAG_WRITE_THROUGH fast 20mal so lange benötigt als ohne? Ich schreibe etwa eine 1 MByte Testdatei auf einen USB-Stick und das braucht fast 2 Minuten mit FILE_FLAG_WRITE_THROUGH, ohne nur wenige Sekunden.

Wenn ich FILE_FLAG_NO_BUFFERING anstatt von FILE_FLAG_WRITE_THROUGH verwende, erhalte ich beim ersten Aufruf von WriteBuffer eine Exception 'Stream-Schreibfehler'.

Es geht mir ja darum, Daten ohne den Windows-Cache zu schreiben. Bei der benötigten Zeit mit FILE_FLAG_WRITE_THROUGH darf ich mir garnicht vorstellen, wie lange eine 100 MByte Datei dauert.

shmia 14. Apr 2010 16:51

Re: Datei physikalisch lesen/schreiben ohne den Windows-Cach
 
Lass doch den Cache seine Arbeit machen.
Wenn die Datei geschrieben wurde, dann kann man ja FlushFileBuffers aufrufen:
Delphi-Quellcode:
stream := TFileStream.Create(....
try
  // hier 100MB schreiben

  FlushFileBuffers(stream.Handle);
  // jetzt ist die Datei sicher auf dem Datenträger
finally
  stream.Free;
end;
Bei einem USB-Stick kann es sein, dass dein Programm sekundenlang in FlushFileBuffers festhängt, weil es die Daten auf das physische Medium schreibt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:27 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz