Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Win32/Win64 API (native code) (https://www.delphipraxis.net/17-win32-win64-api-native-code/)
-   -   Windows.CreateFile() ohne Kompression (https://www.delphipraxis.net/160570-windows-createfile-ohne-kompression.html)

Schwedenbitter 20. Mai 2011 09:08

Windows.CreateFile() ohne Kompression
 
Hallo,

ich betreibe ein paar virtuelle Maschinen mit VirtualBox. Bislang gibt es dort immer noch kein Tool zum Verkleinern der Festplatte. Aus diesem Grunde benutze ich sdelete, um die Platte mit Nullen zu überschreiben und danach dann offline zu verkleinern.

Ich habe sdelete nun inkl. GUI nachgeschrieben. Ich habe aber ein Problem, wenn eine Partition mit NTFS formatiert und die Kompression eingeschaltet wurde. Da sich Nullen extrem gut komprimieren lassen, habe ich de facto eine Endlosschleife. Im Moment ist meine Nullen-Datei ca. 53 GB groß (Tendenz steigend - mal sehen, wie lange das Programm/Windows mitmachen :lol:), verbraucht aber auf der Festplatte nur 4 KB.

Ich habe nun versucht, diese Problem dadurch zu lösen, dass ich FileCreate so aufrufe:
Delphi-Quellcode:
  lHandle:=CreateFile(PChar(lFileName),
    GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
    FILE_FLAG_DELETE_ON_CLOSE Or
    FILE_ATTRIBUTE_NORMAL Or     // -> keine Kompression ?
    FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, 0);
Das scheint es aber irgendwie nicht zu sein. Es gibt in Windows noch eine Konstante [DELPHI]FILE_ATTRIBUTE_COMPRESSED = $00000800;/DELPHI]. Ich ging davon aus, dass die Datei eben nicht komprimiert wird, wenn ich das Bit nicht setze.

Gibt es eine einfach Erklärung/Lösung für mein Problem oder muss ich als Workaround den Umweg über
Delphi-Quellcode:
FSCTL_SET_COMPRESSION
nehmen?


Gruß, Alex

OldGrumpy 20. Mai 2011 09:16

AW: Windows.CreateFile() ohne Kompression
 
Du wirst den Umweg gehen müssen, denn selbst wenn Du das File ohne das Kompressionsflag erzeugst, erbt es trotzdem das Flag des Ordners in dem es erzeugt wird, es sei denn, Du verpasst dem File einen entsprechenden Descriptor. Kommt unterm Strich aber vom Aufwand her aufs Gleiche raus.

Um unnötige Fragmentierung zu vermeiden, solltest Du die Datei erst anlegen und sofort wieder schließen (0 Bytes Größe), dann die Kompression abschalten und erst danach in das File schreiben.

Nebenbei: Eingeschaltete NTFS-Kompression ist der sicherste Weg, seine Kiste zäh und lahm zu machen :D

himitsu 20. Mai 2011 10:06

AW: Windows.CreateFile() ohne Kompression
 
Sowas wie Komprimierung, Verschlüsselung, ReparsePoint und SparseFile sind nunmal keine Dateiattribute, sondern Zustandsmarker.
Diese lassen sich also nicht einfach so als attribute setzen.

DeviceIoControl + FSCTL_SET_COMPRESSION

PS: Gegenüber Zip und Co. ist diese Art der Compression garnicht so langsam wie sie aussieht.

Bei der Compression wird die Datei in kleine Stücke zerlegt und diese Teile einzeln komprimiert. Zum Schluß werden diese Teile als SparseFile abgespeichert, also logisch gesehn liegen diese Teile an der selben Dateiposition, wie die unkomprimierten Teile, nur daß zwischendurch ein paar Stücken fehlen (nur logisch und nicht physisch auf der Platte liegen), so daß man überall in der Datei lesen und schreiben kann, ohne die ganze Datei umkomprimieren zu müssen.

PS: Vor dem Anlegen der Datei dem Ordner/Partition das CompressionFlag entnehmen, denn ist der Ordner komprimiert, dann werden Dateien standardmäßig auch komprimiert.
Ansonsten: Datei erstellen (0 Byte), Komprimierung ändern und dann füllen.

Ach ja, NTFS schafft noch ein paar TB.

Schwedenbitter 20. Mai 2011 10:30

AW: Windows.CreateFile() ohne Kompression
 
Danke für Eure Antworten!

Zitat:

Zitat von himitsu (Beitrag 1101935)
Ach ja, NTFS schafft noch ein paar TB.

Ich hatte keine Lust mehr und daher bei 100 GB aufgehört.

Das mit den Attributen ist schon klar. Komisch ist dann bloß, dass es
Delphi-Quellcode:
Unit Windows;
  FILE_ATTRIBUTE_COMPRESSED          = $00000800;
gibt. Damit lässt sich auch ohne den Umweg über
Delphi-Quellcode:
DeviceIoControl()
ermitteln, ob die Datei komprimiert ist oder eben nicht. Das wiederum brachte mich dann auf die Idee, dass ich es über die Attribute machen könnte.

[EDIT]
Ohne Umweg meint über die Abfrage des Attributes aus dem Record, welches man sich z.B. mit
Delphi-Quellcode:
FindFirstFile()
liefern lässt.
[/EDIT]

Ich habe es jetzt so gelöst:
Delphi-Quellcode:
lHandle:=CreateFile(PChar(lFileName),GENERIC_READ or GENERIC_WRITE,
  0, nil, CREATE_ALWAYS,
  FILE_FLAG_WRITE_THROUGH Or
  FILE_FLAG_NO_BUFFERING Or
  FILE_FLAG_DELETE_ON_CLOSE Or
  FILE_ATTRIBUTE_NORMAL Or // -> kann ich mir dann sparen !
  FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, // müsste ich mir auch sparen können, oder?
  0);

FWritten:=0;                     FillChar(FBuffer, BufferSize, 0);

If (lHandle <> INVALID_HANDLE_VALUE) Then
Try
  lComp:=0; // Kompression ausschalten
  DeviceIoControl(lHandle, FSCTL_SET_COMPRESSION, @lComp, SizeOf(Short), nil, 0, lRes, nil);

  ...
Nochmals Dank für Eure Hilfe, Alex

himitsu 20. Mai 2011 10:47

AW: Windows.CreateFile() ohne Kompression
 
Zitat:

Komisch ist dann bloß, dass es
Delphi-Quellcode:
FILE_ATTRIBUTE_COMPRESSED = $00000800;
gibt.
Sowas nennt passiert durch "Namenskonventionen":
- damit es namentlich zu den anderen Attributen paßt
- da es auch was mit den Dateittributen und den anderen Dateiinhalten zu tun hat (die FILE_FLAGs sind für die Steuerung des Dateidateizugriffs)
- Dieses Attribut wird nur durch den Dateisystemtreiber gesetzt, damit er weiß, ob es komprimiert ist oder nicht.

Schwedenbitter 20. Mai 2011 11:25

AW: Windows.CreateFile() ohne Kompression
 
Also kann ich mir das Setzen der beiden "Attribute" sparen, oder?

Ich hätte dann noch eine Frage:
Ich möchte gern den Schreib-/Lese-Durchsatz einer HDD testen, und zwar unabhängig von der Kompression. Mit Kompression soll diese aktiv bleiben und dem Benutzer ein Bild darüber geben, wie sich das auf die Performance auswirkt.
Das stellt mich vor 2 Probleme bzgl. des zu schreibenden Dateinhalts. Wenn ich (1.) alles Nullen schreibe, endet das im Chaos (Siehe dieses Thema). Wenn ich es (2.) wie bereits prkatiziert so mache, dass ich den Datenpuffer mit Zufallszahlen füttere, dann kann es der hinter der NTFS-Kompression stehende Algorhytmus überhaupt nicht mehr komprimieren. Das mag zwar auf einen Großteil von Systemdateien zutreffen, ist sonst aber unrealistisch...

Wie finde ich also ein Pattern/eine Matrix/ein sonstwas, wo ich eine durchschnittliche Kompression von sagen wir z.B. 1,5:1 erhalte. <- außer druch probieren, wobei mir selbst da ein Ansatz fehlt.

Ich hätte ja schon ein neues Thema aufgemacht, weiß aber nicht so recht, ob das hier in die DelphiPraxis gehört. Für die Suchmaschinen fehlt es mir wiederum an (auch englischen) Suchbegriffen.

Danke, Alex

OldGrumpy 20. Mai 2011 12:15

AW: Windows.CreateFile() ohne Kompression
 
Wenn Du eine Kompression von 1,5 zu 1 realisieren willst, dann erzeuge einfach eine entsprechend granulierte Mischung aus Nullen und Zufallszahlen. Z.B. 32 Bytes Zufallszahlen, 32 Bytes Nullen, 32 Bytes Zufallszahlen. Diese 96 Bytes dampft die Kompression auf annähernd 64 Bytes ein, also deine 1,5:1 (oder 3:2). Je nach gewünschter Blockgröße zum Schreiben kannst Du dann diese Blockgrößen natürlich noch variieren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:33 Uhr.

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