Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Dateien ohne Inhalt (leere Dateien) finden (https://www.delphipraxis.net/170298-dateien-ohne-inhalt-leere-dateien-finden.html)

Schwedenbitter 10. Sep 2012 14:19

Dateien ohne Inhalt (leere Dateien) finden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich habe ein Problem mit meinem Fileserver und hoffe zunächst, die richtige Rubrik innerhalb der :dp: gefunden zu haben.

Nach einem Absturz (Ursache ist hier egal), habe ich jetzt schon ein paar Dateien gefunden, deren Größe <> 0 Bytes ist, deren Inhalt aber wie folgt aussieht:
Code:
00000000   00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00
00000010   00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00
00000020   00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00
Das sollte so nicht sein und ich befürchte, dass es noch ein paar weitere Dateien "erwischt" hat. Ich habe jetzt in meiner Not quick and dirty etwas zusammenprogrammiert, was mir derartige Null-Dateien rekursiv suchen soll, was aber nicht funktioniert. Den vollständigen Code habe ich angehängt. Der Fehler muss aber irgendwo hier liegen:
Delphi-Quellcode:
If (SR.Size > 0) Then                  // 0-Byte-Dateien ignorieren
Begin
   AssignFile(F, Dir + PathDelim + SR.Name);
   System.FileMode:=fmOpenRead;
   {$I-}
   Reset(F);
   If (IOResult = 0) Then
   Begin
      IsEmpty:=True;
      BlockRead(F, Buffer, BuffSize, Res);
      CloseFile(F);
      If (Res > 0) Then
      Begin
         For I:=1 To Res Do
         Begin
            If (Buffer[I] <> 0) Then
            Begin
               IsEmpty:=False;
//             Break;
            End;
         End;
      End;
      If IsEmpty Then
         LBFiles.Items.Append(Dir + PathDelim + SR.Name + ' - (' +
         FormatFloat('0,', SR.Size) + ')');
   End;
   {$I+}
End;
Kann mir jemand helfen, meine Denkblockade aufzulösen?

Danke, Alex

Aphton 10. Sep 2012 14:24

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Genauere Fehlermeldung?

Verrate mir übrigens bitte wie groß die größte Datei ist

Edit1:
Delphi-Quellcode:
  BlockRead(F, Buffer, BuffSize, Res); // #1
  {...}
  For I:=1 To Res Do // #2
  Begin
    If (Buffer[I] <> 0) Then // #2
  {...}
Ich nehme an, dass dein Buffer nicht 0 indiziert ist (= 1 bis n); folglich darfst du bei #1 doch nicht Buffer so alleine angeben, wenn ich mich richtig erinnere.
Probier mal
Delphi-Quellcode:
//..
  BlockRead(F, Buffer[1], BuffSize, Res)
Edit2 Anmerkung nebenbei:
Du kannst übrigens die Schleife schon vorzeitig verlassen und zwar genau dann, wenn diese if Bedingung zutrifft (verwende break dazu...)!

p80286 10. Sep 2012 14:43

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Ist eigentlich ungewöhnlich einen Buffer nicht mit index-0 staten zu lassen (
Delphi-Quellcode:
for i:=0 to res-1...
)

Gruß
K-H

himitsu 10. Sep 2012 14:55

AW: Dateien ohne Inhalt (leere Dateien) finden
 
[edit]
Wollte ich vorhin auch schon fragen.

Was ist "Buffer" ?
Und sicher daß es von 1..Länge geht?

Joar, Fehlerbeschreibungen braucht man ja nicht zu nennen ... jedenfalls nicht, wenn man von uns keine schnelle "hilfreiche" Antwort haben möchte und nee, wir haben niocht immer die Lust/Zeit/Möglichkeit es erst selber auszuprobieren.
Tipp: Strg+C funktioniert fast überall. (auch in Dialogen)

Schwedenbitter 10. Sep 2012 15:03

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Danke für Eure Antworten!

Ich bekomme eine EAccessViolation in der Zeile mit
Delphi-Quellcode:
If (Buffer[I] <> 0) Then
. Nicht mehr und nicht weniger. Warum ist mir völlig unklar. Dabei sieht die Deklaration wie folgt aus:
Delphi-Quellcode:
Const
   BuffSize      = 1024;
Var
   SR            : TSearchRec;
   F            : File;
   Buffer      : Array [1..BuffSize] Of Byte;
   Res         : Integer;
   IsEmpty      : Boolean;
   I            : Integer;
Aber das wollte ich nicht alles hier schreiben. Deshalb hatte ich ja den Quellcode gepackt angefügt. Was genau - zusätzlich zur Fehlermeldung - braucht Ihr noch für eine schnelle Antwort. Ich bin ja durchaus willig...

Die größte Datei ist bislang ca. 1,5 MB. Üblicher Weise beginnen Dateien nicht eben mal mit Nullen. I.d.R. steht am Anfang ein TAG, der die Datei einem bestimmten Typ zuordnet, bei exe-Dateien steht am Anfang 'MZ' etc.
Mir reicht es bei meiner Suche, wenn ich feststelle, dass die ersten 1024 Bytes (oder weniger) ausschließlich Nullen sind. Dann kann ich per Hand nachsehen. Denn nachsehen und die Dateien mit sinvollen Daten aus dem Backup ersetzen muss ich sowieso. Und weil es um ca. 200 GB an Daten geht, kann/will ich die Dateien nicht komplett auslesen.

Die Schleife werde ich später vorzeitig beenden. Das
Delphi-Quellcode:
break
steht ja schon auskommentiert da 8-)

Warum ich bei 1 und nicht bei 0 mit dem Index angefangen habe, weiß ich auch nicht.

Ich habe jetzt
  • das Array von 0 bis 1023 definiert,
  • habe bei BlockRead Buffer[0] angegeben und
  • lasse die Schleife von 0 bis
    Delphi-Quellcode:
    Pred(Res)
    laufen
und bekomme trotzdem noch die EAccessViolation.

[edit]
Falls jemand eine leere Datei zum Testen braucht, kann ich die liefern. Gepackt dürfte die ja nicht sehr groß sein ;-)
[/edit]

Mavarik 10. Sep 2012 15:07

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Je nachdem was Buffer ist...

Schreibst Du nicht ins Array sondern an die Adresse der Array Variable...

daher immer Buffer[0] verwenden...

Mavarik

Schwedenbitter 10. Sep 2012 15:18

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Ich bin ein Stück weiter. Den Verursacher habe ich gefunden, nicht aber die Ursache. Der Code sieht modifiziert wie folgt aus:
Delphi-Quellcode:
BlockRead(F, Buffer[0], SizeOf(Buffer), Res);
CloseFile(F);
If (Res > 0) Then
Begin
   ShowMessage(SR.Name + #13 + 'Es wurden ' + FormatFloat('0,', Res) + ' Bytes gelesen.');
   ...
Das für mich verblüffende ist die Meldung
Code:
Urlaub.xls
Es wurden 4.469.406 Bytes gelesen.
Die Datei ist natürlich keine 4 MB groß. Wieso liefert mir BlockRead einen falschen Wert zurück?

Schwedenbitter 10. Sep 2012 15:25

AW: Dateien ohne Inhalt (leere Dateien) finden
 
:dancer: ich habe den Fehler(?) soeben selbst gefunden!

Ich habe
Delphi-Quellcode:
Reset(F);
in
Delphi-Quellcode:
Reset(F, 1);
geändert. Jetzt hat
Delphi-Quellcode:
Res
die richtige Größe und meine Schleife rennt nicht mehr über das Ende hinaus.
Ich frage mich trotzdem, warum das so fatal ist. Lt. Hilfe wird ohne Angabe eine Blockgröße von 128 verwendet. Aber selbst wenn, dann wären 128 x 1024 lediglich 131.072 und nicht ca. 4 Mio...

Danke für Eure Hilfe!

himitsu 10. Sep 2012 15:50

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Ich würde dir einfach mal empfehlen, dich mit Streams zu beschäftigen.

Nja, wenn keine RecSize angegeben ist, dann wird 128 verwendet. (das ist die Größe des Standard-Puffers, welcher für diese alten Dateiopertionen verwendet wird).
Bei typisierten Dateien (
Delphi-Quellcode:
var F: File of Byte;
) wird die Größe des Typs als RecSize verwendet.

[add]
PS: Du wirst es nicht glauben, aber das steht sogar in der OH (falls man diese lesen würde)
Zitat:

RecSize ist ein optionaler Ausdruck, der nur bei untypisierten Dateien angegeben werden kann. Wenn F eine untypisierte Datei ist, gibt RecSize die Blockgröße für Datenübertragungen an. Wenn Sie RecSize nicht angeben, wird der Standardwert 128 verwendet.

Schwedenbitter 10. Sep 2012 15:58

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Zitat:

Zitat von himitsu (Beitrag 1182369)
Ich würde dir einfach mal empfehlen, dich mit Streams zu beschäftigen.

Das habe ich schon - in anderen Projekten. Ich schrieb ja nicht umsonst in meinem ersten Beitrag quick and dirty. Ich habe in Anbetracht der sich zerlegenden HDD meines Servers im Moment leider andere Probleme als schicken Code mit TFileStream & Co. zu erstellen.

Zitat:

Zitat von himitsu (Beitrag 1182369)
...
Bei typisierten Dateien (
Delphi-Quellcode:
var F: File of Byte;
) wird die Größe des Typs als RecSize verwendet.

Alles klar. Dann verstehe ich auch, warum meine anderen Codes mit BlockRead nie Probleme machten. Dort hatte ich - per Zufall also - immer typisierte Dateivariablen deklariert. Danke für die Erklärung.

himitsu 10. Sep 2012 16:11

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Joar, ich kenn das.
Hatte vor Jahren mal beim Backup probleme bekommen, wo es mir auch noch die Backupplate zerschoß.

Bei der Datenwiederherstellung und vorallem nach Checkdisk waren dann plötzlich viele Dateien 0 Byte groß und oftmals waren ganze Dateien oder nur einer/mehrere Cluster innerhalb von Dateien mit 0 gefüllt.
Hatte mir da auch ein suchprogrämmchen geschrieben, aber ich glaub das Progrämmchen hab'sch inzwischen gelöscht.

Bummi 10. Sep 2012 16:15

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Delphi-Quellcode:
implementation
{$R *.dfm}

type
 TBuff=Array[0..1023] of Byte;
var
 EmptyBuff:TBuff;

procedure TForm6.Button2Click(Sender: TObject);
var
 fs:TFileStream;
begin
   fs:=TFileStream.Create('C:\temp\log.txt',fmCreate);
   fs.Write(EmptyBuff[0],200);
   fs.Free;
end;

procedure TForm6.FormCreate(Sender: TObject);
begin
  ZeroMemory(@EmptyBuff[0],1023)
end;

Function FileIsEmpty(fn:String):Boolean;
var
 fs:TFileStream;
 Buff:TBuff;
 read:Integer;
 i:Integer;
begin
  ZeroMemory(@Buff[0],1023);
  fs:=TFileStream.Create(fn, fmOpenread);
  try
  read := fs.Read(Buff[0],1024);
  Result := true;
  for I := 0 to read-1 do Result := Result and (EmptyBuff[i]= Buff[i]);

  finally
    fs.Free;
  end;
end;

p80286 10. Sep 2012 16:18

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Soo groß ist der Unterschied zwischen TFileStream und Blockwrite ja nun auch nicht:
Delphi-Quellcode:
const
  maxbuffsize=1024;
var
  buffer : array [0..maxbufsize-1];
  f : file;


assignfile(f,'Myfile');
reset(f,1);
repeat
  readed:=blockread(f,buffer,maxbuffsize); {bei nicht dyn arrays geht das! }
  if readed>0 then machwasdamit;
until readed<maxbufsizes;
closefile(f);
Delphi-Quellcode:
const
  maxbuffsize=1024;
var
  buffer : array [0..maxbufsize-1];
  f : tfilestream;

f:=tfilestream.Create('Myfile',fmopenread or fmsharedenynone);
repeat
  readed:=f.read(buffer,maxbuffsize); {bei nicht dyn arrays geht das! }
  if readed>0 then machwasdamit;
until readed<maxbufsizes;
f.free;
Ich hab auch lange einen Bogen darum gemacht.

Gruß
K-H

Schwedenbitter 10. Sep 2012 17:27

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Zitat:

Zitat von himitsu (Beitrag 1182373)
Joar, ich kenn das.
Hatte vor Jahren mal beim Backup probleme bekommen, wo es mir auch noch die Backupplate zerschoß.

Bei der Datenwiederherstellung und vorallem nach Checkdisk waren dann plötzlich viele Dateien 0 Byte groß und oftmals waren ganze Dateien oder nur einer/mehrere Cluster innerhalb von Dateien mit 0 gefüllt.
Hatte mir da auch ein suchprogrämmchen geschrieben, aber ich glaub das Progrämmchen hab'sch inzwischen gelöscht.

Dann muss ich doch mal ausholen:

Mein Fileserver basiert auf openSUSE 11.4 mit Samba. Das Filesystem ist laut fsck in Ordnung. Die Dateien sind bemerkenswerter Weise auf nicht 0 Bytes groß. Dass wäre unter Linux ohne Verrenkungen ein Einzeiler mit dem schönen Befehlt grep.

Nach dem Crash haben die Dateien dieselbe Größe. Nur eben alles voller sinnloser Nullen. Den Code muss ich noch etwas ändern. Ich habe gerade festgestellt, dass iso-Dateien am Anfang auch "leer" sind und erst nach ca. 32KB etwas sinnvolles kommt. Ich habe daher meinen Puffer mal sicherheitshalber auf 524288 Bytes erhöht. Das kostet nicht soviel Zeit, macht aber die Ergebnisse sicherer.

Die ersten Durchläufe sind Dank Eurer Hilfe schon erledigt. Ich weiß jetzt, dass ich eine Menge Datenmüll habe. Glücklicherweise hat aber mein Backup-Server das getan, was er tun soll, nämlich die laufenden Daten zu sichern. Dass mein wöchentliches Backup Schrott ist, kann ich damit verkraften. Zudem ist der Crash am Wochenende passiert, so dass nicht soviel Daten betroffen sind. Arbeit macht es trotzdem.

Soll ich das fertige Produkt nochmal hochladen, für den Fall, dass eines fernen Tages jemand dasselbe Problem hat?

Gruß, Alex

himitsu 10. Sep 2012 17:42

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Dateisysteme sind ja oftmals in Cluster aufgeteilt.

Wenn bei der Reparatur ein Cluster nicht gelesen werden kann, oder wenn die Vrlinkung der Cluster nicht mehr korrekt ist, dann ersetzen viele Reparaturprogramme diese Cluster durch "Neue", welche eben "leer" sind.

Darum hatte ich mein Programm eben auch so geschrieben, daß jeder Cluster einzeln geprüft wird (bzw. mehrere Cluster einlesen, aber auch einzeln prüfen, damit es schneller geht).
Wenn die Festplate selber defekt ist/war, dann sollte man besser Anhand der Sektorgröße prüfen. (z.B. 512 Byte bei HDDs und Speicherkarten / 4 KB bei CDs und DVDs)

hathor 11. Sep 2012 07:06

AW: Dateien ohne Inhalt (leere Dateien) finden
 
@Schwedenbitter

Ich habe den Eindruck, dass Du nur Symptome suchst und Dir den HDD-Inhalt "schön kopierst".
Ob die Daten nicht korrupt sind, erfährst Du vielleicht nur zufällig, wenn KEIN Backup von einzelnen Files existiert.

Was ist denn der Grund für den Crash?
Kann er wieder auftreten?
Wie lässt er sich vermeiden?
Wie sind die SMART-Werte der HDD?
Auf eine gecrashte HDD sollte NIE wieder etwas geschrieben werden,
selbst das Lesen ist KEINE vertrauenswürdige Aktion!

Manche "Rettungsprogramme" (besonders die von Microsoft!) machen noch mehr kaputt.

Mavarik 11. Sep 2012 13:14

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Zitat:

Zitat von p80286 (Beitrag 1182376)
Soo groß ist der Unterschied zwischen TFileStream und Blockwrite ja nun auch nicht:
Gruß
K-H

Unterschied? Beide Aufrufe laufen doch sowieso über die gleiche Kernel32 FileIO Routinen. Ich Denke, wenn ich mir den ASM Code anschaue ist die Blockread Variante noch etwas kürzer...

Mavarik

himitsu 11. Sep 2012 13:26

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Es ist nicht wirklich identisch.

Die alten Pascalfunktionen besitzen teilweise ein eigenes Caching und das ist noch nichtmal annähernd optimal eingestellt.
Die Sache mit dem OOP und der Codevervollständigung braucht man wohl nicht mehr zu erwähnen.
Die alten Funktionen greifen auf gloable Variablen zu. Oder hast du etwa erwartet, daß Delphi-Referenz durchsuchenReset die Datei wirklich nur ReadOnly öffnet? (dieses wird über eine globale Variable Delphi-Referenz durchsuchenFileMode geregelt, mit sehr netten Nebenwirkungen)

p80286 11. Sep 2012 14:42

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Nicht das wir uns mißverstehen, ich wollte nur sagen, daß für den Codierer sich nicht viel ändert.
Und seit XP SP2 ist die Stream-Variante nie langsamer als das alte Blockread.

Gruß
K-H

BUG 11. Sep 2012 15:30

AW: Dateien ohne Inhalt (leere Dateien) finden
 
Ehrlich gesagt fand ich die "klassischen" Dateioperationen immer etwas unübersichtlich. Streams sind (imho) irgendwie übersichtlicher.

Zitat:

Zitat von Schwedenbitter (Beitrag 1182386)
Soll ich das fertige Produkt nochmal hochladen, für den Fall, dass eines fernen Tages jemand dasselbe Problem hat?

Schaden kann es nicht :wink:


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:55 Uhr.

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