Einzelnen Beitrag anzeigen

Muetze1
(Gast)

n/a Beiträge
 
#10

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 10:16
Zitat von Luckie:
Das war nur so mal eben schnell dahin getippt. Es ist natürlich richtig, dass man einfach ein raise macht und keine neue Exception wirft. Wie würdest du es lösen?
Bezugnehmend auf dein Beispiel wo du es direkt darauf anlegst die Exceptions ausserhalb des Aufrufes zu fangen: gar keinen Except Block. Nur ein finally Block als Resourcenschutzblock für die Instanz, eventuelle Exceptions gehen nach draussen und werden gefangen und die Instanz wird definitiv freigegeben.

Im gesamten dann:

Delphi-Quellcode:
procedure Tfrm_main.Button1Click(Sender: TObject);
begin
  try
    if DateiSchreiben(ExtractFilePath(ParamStr(0)) + Edit2.Text, StrToIntDef(Edit1.Text, 0)) then
      MessageDlg('Datei wurde erfolgreich gespeichert.', mtInformation, [mbOk], 0);
  except
    on e:exception do
      MessageDlg(format('Es ist beim Schreiben der Datei ein Fehler aufgetreten.'#10#13#10#13'(%s) %s', [E.Classname, E.Message]),
                 mtError, [mbOk], 0);
  end;
end;

function DateiSchreiben(const AFilename: string; const AFileSize: Int64);
const
  coBlockSize = 16384;
var
  lStream: TStream;
  lFileData: string;
  lBytesToWrite: Int64;
  lWritten: Integer;
begin
  result := false;

    // Erstmal den Stream öffnen. Wenn das nicht klappt, brauch ich kein Array...
  lStream := TFileStream.Create(AFilename, fmCreate or fmShareDenyWrite);
  try
    lFileData := StringOfChar(coBlockSize, #55);

    lBytesToWrite := AFileSize;
    while ( lBytesToWrite > 0 ) do
    begin
      lWritten := lStream.WriteBuffer(lFileData[1], Min(lBytesToWrite, coBlockSize));

      if lWritten <> Min(lBytesToWrite, coBlockSize) then
        exit;

      Dec(lBytesToWrite, lWritten);
    end;

    result := true;
  finally
    lStream.free;
  end;
end;
Warum so?

1. Ein dynamisches Array ohne Begrenzung ist schlecht, weil bei einer 2 GB Datei möchte ich mal sehen, was zu der Speichermanager zu der Alloziierung sagt.
2. Da die Daten immer gleich waren, hat es sich hier angeboten StringOfChar() zu nutzen.
3. Exceptions, egal wo, werden geworfen und kommen so richtig beim Aufrufer an.
4. Der Rückgabewert gibt den eigentlichen Erfolg zurück. Man kann alternativ mit der Verlagerung des Exception Handlers in die Funktion diese zu einer reinen Funktion machen, die alles über das result regelt.
5. Oberfläche und Implementation sind getrennt. Alles wichtige was die Funktion braucht, wird ihr übergeben und ausserhalb entsprechend aufbereitet.

Und allgemeiner Hinweis: Wenn es nur darum geht eine Platzverschwendung mit bestimmter Größe zu erzeugen, dann einfach TFileStream anlegen und die Size Property setzen. Der Inhalt der Datei ist dann aber Zufall.

Zitat von p80286:
Naja halte ich für Geschmackssache.
Und genau dies ist es eben nicht. Es ist keine reine Geschmackssache sondern eine offene Fehlerstelle. False ist mit 0 definiert und kann direkt verglichen werden. True ist alles was nicht false ist, somit alles ungleich 0. Die Konstante True ist aber nicht mit der Menge der ganzen Zahlen exklusiv der 0 definiert, sondern mit einem einzigen Ordinalwert (1 oder -1? Weiss es gerade nicht genau) und darin liegt das Problem. Wenn du direkt vergleichst, sagst du dem Compiler: Wenn das direkt und nur dieser Wert ist, dann mache. Wenn du den direkten Vergleich weglässt, dann evaluiert die IF Anweisung selbst und das setzt der Compiler auf ein ungleich 0 Vergleich um. Und das ist nicht Geschmackssache sondern ein riesiger Unterschied!
  Mit Zitat antworten Zitat