AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

ReadFile und WriteFile

Ein Thema von Schwedenbitter · begonnen am 29. Jun 2008 · letzter Beitrag vom 1. Jul 2008
Antwort Antwort
Seite 1 von 2  1 2      
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#1

ReadFile und WriteFile

  Alt 29. Jun 2008, 22:42
Hallo,

ich habe ein Problem mit dem Befehl WriteFile. Ich benutze Delphi 6. Wenn ich die folgenden Befehle ausführen lasse, bekomme ich immer nur eine 0-Byte-Datei:

Delphi-Quellcode:
Var
   NR,SB : Cardinal;
   Buffer : Array [1..5120] Of Byte;
   FHandle : Cardinal;
Begin
   SB:=SizeOf(Buffer);
   FHandle:=CreateFile(PChar('C:\Test.$$$'),
                       GENERIC_READ or GENERIC_WRITE,
                       0,
                       nil,
                       CREATE_ALWAYS,
                       FILE_FLAG_NO_BUFFERING or FILE_FLAG_WRITE_THROUGH,
                       0);
   If FHandle <> INVALID_HANDLE_VALUE Then
   Begin
      WriteFile(FHandle,Buffer,SB,NR,nil);
      FileClose(FHandle);
   End;
End;
Die Lese-/Schreibrechte sind nicht das Problem. Die Datei wird angelegt/überschrieben. Es muss also an WriteFile liegen.

1. Was mache ich falsch?
2. Wo gibt es eine schöne (und ggf. deutsche) Beschreibung für CreateFile, WriteFile, ReadFile etc.?
Alex Winzer
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#2

Re: ReadFile und WriteFile

  Alt 29. Jun 2008, 22:59
Hallo,

ich würde den Rückgabewert von WriteFile() beobachten. So richtig etwas falsches habe ich nicht sehen können, darum habe ich den Code mal mit D7 übersetzt - und er tut was er soll.

Delphi-Quellcode:
Begin
  SB := SizeOf(Buffer);
  FHandle := CreateFile(
    'C:\daten\DP\Test.$$$', GENERIC_READ or GENERIC_WRITE, 0, nil,
    CREATE_ALWAYS, FILE_FLAG_NO_BUFFERING or FILE_FLAG_WRITE_THROUGH, 0
  );
  if FHandle <> INVALID_HANDLE_VALUE then
  begin
    if WriteFile(FHandle, Buffer, SB, NR, nil)
      then ShowMessage(IntToStr(NR))
      else ShowMessage(SysErrorMessage(GetLastError));
    FileClose(FHandle);
  end;
end;
Grüße vom marabu
  Mit Zitat antworten Zitat
Apollonius

Registriert seit: 16. Apr 2007
2.325 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: ReadFile und WriteFile

  Alt 29. Jun 2008, 23:05
Es ist nur inkonsequent, am Ende FileClose aufzurufen. Zu CreateFile gehört CloseHandle. FileClose macht zwar intern auch nichts anderes, aber FileClose gehört eigentlich zu FileOpen.
Wer erweist der Welt einen Dienst und findet ein gutes Synonym für "Pointer"?
"An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function."
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.116 Beiträge
 
Delphi 11 Alexandria
 
#4

Re: ReadFile und WriteFile

  Alt 29. Jun 2008, 23:14
Moin Schwedenbitter,

da kann ich mich Marabu nur anschliessen.
Funktioniert problemlos.
Bei mir auch mit D7 getestet, unter XP Pro SP 2, und voll gepatcht.
Mit welchem Betriebssystem arbeitest Du?
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#5

Re: ReadFile und WriteFile

  Alt 29. Jun 2008, 23:55
@ Alle

Es stimmt, der Code funktioniert auch bei mir. Erstmal danke für den Tipp mit SysErrorMessage(GetLastError). Das kannte ich nicht.
Allerdings ist mein Code von oben nur ein Ausschnitt. Wenn ich den nehme, mit Delphi ein neues Programm aufmache, den Teil reinkopiere und ausführen lasse, dann klappt es. Der Fehler muss also am Rest des Codes liegen. Deshalb hier mal alles:
Delphi-Quellcode:
Procedure TForm1.Start1Click(Sender: TObject);
Var
   I               : Word;
   NR,SB            : Cardinal;
   Buffer         : Array [1..5120] Of Byte;
   FHandle         : Cardinal;
   E1,E2,CB         : Boolean;
Begin
   Ende:=False;
   SB:=SizeOf(Buffer);
   {Tastenstatus merken und deaktivieren}
   E1:=Edit1.Enabled;
   Edit1.Enabled:=False;
   E2:=Edit2.Enabled;
   Edit2.Enabled:=False;
   CB:=CB1.Enabled;
   CB1.Enabled:=False;
   Start1.Visible:=False;
   Stop1.Visible:=True;
   {Puffer mit Zufallszahlen füllen}
   Randomize;
   FillChar(Buffer,SB,0);
   For I:=1 To SB Do
   Begin
      Buffer[I]:=Random(256);
   End;
   {Datei anlegen}   
   FHandle:=CreateFile(PChar(Edit1.Text),
                       GENERIC_READ or GENERIC_WRITE,
                       0,
                       nil,
                       CREATE_ALWAYS,
                       FILE_FLAG_NO_BUFFERING or FILE_FLAG_WRITE_THROUGH,
                       0);
   { Jetzt schreiben}
   If FHandle<>INVALID_HANDLE_VALUE Then
   Begin
      If CB1.Checked Then
      Begin
         Repeat
            WriteFile(FHandle,Buffer,SB,NR,nil);
            Application.ProcessMessages;
         Until (NR<SB) Or Ende;
      End
      Else
      Begin
         If WriteFile(FHandle,Buffer,SB,NR,nil)
            Then ShowMessage(IntToStr(NR))
         Else ShowMessage('Mist: '+SysErrorMessage(GetLastError));
      End;
      {Datei schließen}
      //FileClose(FHandle);
   End;
   {Tastenstatus wiederherstellen}
   Edit1.Enabled:=E1;
   Edit2.Enabled:=E2;
   CB1.Enabled:=CB;
   Start1.Visible:=True;
   Stop1.Visible:=False;
End;
Wie gesagt: Das Anlegen klappt, nur die Datei ist leer.
Edit1 ist TEdit und fragt den Dateinamen ab.
Edit2 ist TEdit und fragt die Größe ab -> noch nicht implementiert.
CB1 ist TCheckBox und gibt an, ob der Datenträger voll (NR<SB) geschrieben werden soll: Beide Varianten produzieren nur eine 0-Byte-Datei.

Existiert die Datei nicht und wird neu angelegt, bringt mir SysErrorMessage(GetLastError) die Meldung Falscher Parameter. Was mir das sagen soll, weiß ich nicht. Wenn die Datei nur überschrieben wird, kommt überhaupt keine Meldung <--- Das verstehe ich nun überhaupt nicht. Nach meinem begrenzten Verständnis müsste doch immer eine Meldung kommen: Entweder mit Fehler oder mit den geschriebenen Bytes. Das Programm stürzt auch nicht ab, sondern tut weiter so als wäre nichts gewesen...

XP SP3 (32bit) mit allen Patches nach SP3.

Dankbar für weitere Ideen und Gute Nacht

Alex
Alex Winzer
  Mit Zitat antworten Zitat
Christian Seehase
(Co-Admin)

Registriert seit: 29. Mai 2002
Ort: Hamburg
11.116 Beiträge
 
Delphi 11 Alexandria
 
#6

Re: ReadFile und WriteFile

  Alt 30. Jun 2008, 01:55
Moin Alex,

wie sieht denn bei D6 die Deklaration von WriteFile aus?

In D7 sieht es so aus:

Delphi-Quellcode:
function WriteFile(hFile: THandle; const Buffer; nNumberOfBytesToWrite: DWORD;
  var lpNumberOfBytesWritten: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
Tschüss Chris
Die drei Feinde des Programmierers: Sonne, Frischluft und dieses unerträgliche Gebrüll der Vögel.
Der Klügere gibt solange nach bis er der Dumme ist
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#7

Re: ReadFile und WriteFile

  Alt 30. Jun 2008, 06:45
Moin,

die API Funktion WriteFile hat sich wohl nie geändert und D6 übersetzt den Code ohne Fehler, also wird schon alles in Ordnung sein. Durch das Verarbeiten von Nachrichten innerhalb der Schleife soll wohl dem Benutzer des Programms eine Abbruch-Möglichkeit gegeben werden. Das dürfte aber bei vernünftiger Handhabung keinen Einfluß auf die Dateigröße nehmen. Wenn FileClose() allerdings immer auskommentiert war, dann ist eine leer Datei ein durchaus zu erwartendes Ergebnis. Beim Grübeln konnte ich es mir nicht verkneifen den Code etwas umzugestalten.

Delphi-Quellcode:
const
  BUFSIZE = 5120;

var
  // ...
  buffer: array [1..BUFSIZE] of Bytes;
  writeOnce, writeFailed, writeCanceled: Boolean;
  bytesWritten: Cardinal;
begin
  // ...
  writeCanceled := False;
  writeOnce := not CB1.Enabled;
  if FHandle <> INVALID_HANDLE_VALUE then
  begin
    repeat
      writeFailed := not WriteFile(FHandle, buffer, BUFSIZE, bytesWritten, nil);
      Application.ProcessMessages;
    until writeOnce or writeFailed or writeCanceled or (BytesWritten < BUFSIZE);
    if writeFailed then
      ShowMessage('Mist: ' + SysErrorMessage(GetLastError));
    CloseHandle(FHandle);
  end;
  // ...
end;
Freundliche Grüße
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#8

Re: ReadFile und WriteFile

  Alt 30. Jun 2008, 10:46
Zitat von marabu:
... Wenn FileClose() allerdings immer auskommentiert war, dann ist eine leer Datei ein durchaus zu erwartendes Ergebnis. Beim Grübeln konnte ich es mir nicht verkneifen den Code etwas umzugestalten.
FileClose() war zunächst nicht auskommentiert. Ich habe es dann aber aufgrund des Hinweises von Apollonius so gehandhabt. Das Ergebnis meines Code-Ausschnittes hat sich dabei aber nicht verändert. Ich hatte auch ohne FileClose eine 5.120 Byte große Datei. Folglich glaube ich nicht daran, dass es schlicht daran liegen soll. Ich werde mal CloseHandle() reinbauen. Ich sehe so richtig nicht den Unterschied zwischen meinem Ausschnitt und dem was ich von meinem Programm ausgeführt haben wollte.

Dass mit dem korrigieren des Codes ist OK. Ich will ja was lernen. Die Deklaration von WriteFile ist auch bei Delphi 6 schon so. Ich werde es heute Abend wieder probieren. Bin jetzt auf Arbeit und habe hier kein Delphi

Schönen Tag wünscht Alex
Alex Winzer
  Mit Zitat antworten Zitat
Schwedenbitter

Registriert seit: 22. Mär 2003
Ort: Finsterwalde
622 Beiträge
 
Turbo Delphi für Win32
 
#9

Re: ReadFile und WriteFile

  Alt 30. Jun 2008, 21:01
Schade:

Ich habe die Änderungen in meinen Quellcode übernommen. Er schreibt die Datei trotzdem nicht.

Da der Code doch etwas länger ist, habe ich hier mal die Dateien gepackt. Ich würde mich freuen, wenn sich das mal jemand von Euch Profis zu Gemüte führen könnte. Ich möchte am Ende ein Programm haben, dass mir die Platte vollschreibt und wieder liest und mit GetTickCount die Zeit ermittelt. Ich weiß: Gibt es zu Hauf. Aber ich wollte es eigentlich selber machen und bin kurz davor zu BlockRead() und BlockWrite() zurückzukehren.
Auf WriteFile() bin ich nur gekommen, weil man da mit den entsprechenden Optionen versuchen kann, Windows zum Schreiben ohne Cache etc. zu zwingen...

Gruß, Alex
Alex Winzer
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#10

Re: ReadFile und WriteFile

  Alt 30. Jun 2008, 22:13
Hi Alex,

Zitat von Schwedenbitter:
... Ich habe die Änderungen in meinen Quellcode übernommen. ...
nicht wirklich.

Ich habe das dann mal für dich gemacht und dann sieht das so aus:

Delphi-Quellcode:
Const
  BuffSize = 1 shl 20; // genau 1,0 MB

var
  Buffer: Array [1..BuffSize] Of Byte;

Procedure TForm1.Start1Click(Sender: TObject);
Var
  I: Cardinal;
  FHandle: Cardinal;
  WriteFailed, WriteCanceled: Boolean;
  BytesWritten: Cardinal;
  E1,E2,CB: Boolean;
begin
  // ...
        { Jetzt schreiben}
        If FHandle<>INVALID_HANDLE_VALUE Then
        Begin
          if CB1.Checked
            then I := MaxInt
            else I := StrToInt(Edit2.Text);
       Repeat
            WriteFailed:=not WriteFile(FHandle,Buffer,BuffSize,BytesWritten,nil);
            Dec(I);
            Application.ProcessMessages;
          Until WriteCanceled Or WriteFailed Or (I=0) or (BytesWritten<BuffSize);
          If WriteFailed Then
            ShowMessage('Mist: ' + SysErrorMessage(GetLastError));
          {Datei schließen}
          CloseHandle(FHandle);
        End;
  // ...
end;
Ein MegaByte musst du nicht selbst ausrechnen, das macht der Compiler für dich - wenn du willst. Den Buffer solltest du nicht lokal zur Prozedur deklarieren, er könnte den Stack sprengen. Beim Benennen deiner Komponenten und Variablen bist du noch nicht sehr konsistent, lies dazu mal einen Style-Guide. Beim Auffangen des Rückgabewertes von WriteFile() hast du die Semantik invertiert, so dass Erfolg zu Misserfolg umgemünzt wurde.

Vergleichbare Ergebnisse erhältst du mit deiner Programmidee nie. Du kannst zwar den einen oder anderen Cache eliminieren, aber die aktuelle Verteilung von freiem Speicherplatz dürfte von Festplatte zu Festplatte stark abweichen.

Trotzdem noch viel Spaß mit deinem Projekt.

Freundliche Grüße
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:38 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