Delphi-PRAXiS
Seite 3 von 4     123 4      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi StreamWrite erzeugt nur 0 Byte-File (https://www.delphipraxis.net/115063-streamwrite-erzeugt-nur-0-byte-file.html)

shmia 17. Jun 2008 11:49

Re: StreamWrite erzeugt nur 0 Byte-File
 
WriteBuffer hat den Vorteil, dass man sich selbst um nichts kümmern muss.
WriteBuffer erzeugt eine Exception, wenn das Zielmedium die Daten nicht aufnehmen kann (z.B. Platte voll oder Schreibfehler wg. defektem Sektor)
Delphi-Quellcode:
procedure TStream.WriteBuffer(const Buffer; Count: Longint);
begin
  // wenn Count=0 ist, passiert gar nichts
  // andernfalls werden Count Bytes geschrieben
  if (Count <> 0) and (Write(Buffer, Count) <> Count) then
    // falls beim Schreiben ein Fehler aufgetreten ist, wird eine Exception erzeugt
    raise EWriteError.CreateRes(@SWriteError);
end;
Deshalb empfehle ich WriteBuffer anstelle von Write zu verwenden.

Muetze1 17. Jun 2008 11:53

Re: StreamWrite erzeugt nur 0 Byte-File
 
Nun gut, dann umgestellt um die Exception von WriteBuffer() zu nutzen...

Delphi-Quellcode:
function DateiSchreiben(const AFilename: string; const AFileSize: Int64): boolean;
const
  coBlockSize = 16384;
var
  lStream: TStream;
  lFileData: string;
  lBytesToWrite: Int64;
  lWriteCount: Int64;
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(#55, coBlockSize);

    lBytesToWrite := AFileSize;
    while ( lBytesToWrite > 0 ) do
    begin
      lWriteCount := Min(lBytesToWrite, coBlockSize);

      lStream.WriteBuffer(lFileData[1], lWriteCount);

      Dec(lBytesToWrite, lWriteCount);
    end;

    result := true;
  finally
    lStream.free;
  end;
end;
Ja, wieder im Beitragseditor geschrieben und ungetestet. Also keine Schläge, wenn wieder Kleinigkeiten falsch sind...

DevidEspenschied 17. Jun 2008 11:54

Re: StreamWrite erzeugt nur 0 Byte-File
 
Ja, das war wohl der ausschlaggebende Punkt.

Nun habe ich aber das Problem, nicht etwa einen String wie lFileData mit identischen Zeichen (hier #55, also die Ziffer 7), sondern einem Testmuster schreiben zu wollen. Hierfür habe ich ein 64 Zeichen großes Muster defininiert:

Delphi-Quellcode:
CONST TestMuster = '#abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+';
Wenn ich nun aber TestMuster anstatt von lFileData[1] in der Write-Funktion verwende, wird das Muster nur einmal geschrieben, und der Rest ist Datensalat. Wie könnte man das Beispiel denn abändern, so dass dieses Testmuster fortlaufend geschrieben wird ? Mit 64 Byte kann ich da bspw. Dateigrößen von 1, 4 oder 16 MByte abdecken, da diese durch 64 ohne Rest teilbar sind.

Muetze1 17. Jun 2008 11:59

Re: StreamWrite erzeugt nur 0 Byte-File
 
Der jetzige Code deckt alle Dateigrößen ab, auch ungerade :warn:

Delphi-Quellcode:
function DateiSchreiben(const AFilename: string; const AFileSize: Int64): boolean;
const
  coFileData = '#abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+';
var
  lStream: TStream;
  lBytesToWrite: Int64;
  lWriteCount: Int64;
begin
  result := false;

    // Erstmal den Stream öffnen. Wenn das nicht klappt, brauch ich kein Array...
  lStream := TFileStream.Create(AFilename, fmCreate or fmShareDenyWrite);
  try
    lBytesToWrite := AFileSize;
    while ( lBytesToWrite > 0 ) do
    begin
      lWriteCount := Min(lBytesToWrite, length(coFileData));

      lStream.WriteBuffer(coFileData, lWriteCount);

      Dec(lBytesToWrite, lWriteCount);
    end;

    result := true;
  finally
    lStream.free;
  end;
end;
Wieder ungetestet, aber sollte so klappen.

DevidEspenschied 17. Jun 2008 12:39

Re: StreamWrite erzeugt nur 0 Byte-File
 
Danke, das Beispiel funktioniert einwandfrei.

Nun habe ich bspw. den Fall, die zuvor geschriebenen Testmusterdaten wieder lesen und überprüfen zu wollen, wozu ich einerseits die Create-Zeile wiefolgt abändere:

Delphi-Quellcode:
lStream := TFileStream.Create(AFilename, fmOpenRead);
und andererseits eine lokale Stringvariable namens ReadMuster deklariere sowie ReadBuffer einsetze:

Delphi-Quellcode:
CONST TestMuster = '#abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+';
VAR ReadMuster : STRING;
BEGIN
...
DateiStream.ReadBuffer(ReadMuster, lReadCount);
IF ReadMuster <> TestMuster THEN ShowMessage('Gelesenes Muster stimmt nicht mit dem Testmuster überein.');
...
Beim Debuggen wird diese Funktion auch durchgeführt, aber ich kann auf den String ReadMuster nicht zugreifen (hier erscheint eine Exception). Das beginnt mit der IF-Abfrage direkt nach ReadBuffer. Wie kann man das am besten lösen ?

Muetze1 17. Jun 2008 13:38

Re: StreamWrite erzeugt nur 0 Byte-File
 
Der String ist leer. Setze die entsprechende Stringlänge bevor du was einliest. Delphi-Referenz durchsuchenSetLength

DevidEspenschied 17. Jun 2008 15:25

Re: StreamWrite erzeugt nur 0 Byte-File
 
Also richtig will das noch nicht funktionieren. Mein bisheriger Code:

Delphi-Quellcode:
VAR  DateiStream : TStream;
      lBytesToRead,
      lReadCount  : Int64;
      ReadMuster  : STRING[64];
CONST TestMuster = '#abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+';
BEGIN
  TRY
    TRY
      DateiStream:=TFileStream.Create(LW+':\'+Datei, fmOpenRead);
      IF DateiStream.Size MOD Length(TestMuster) <> 0 THEN Result:=False ELSE
      BEGIN
        lBytesToRead:=SizeInMByte * 1024 * 1024;
        WHILE (lBytesToRead) > 0 DO
        BEGIN
          lReadCount:=Min(lBytesToRead, Length(TestMuster));

          SetLength(ReadMuster, 64);
          ReadMuster:='';
          DateiStream.ReadBuffer(ReadMuster, lReadCount);

          IF ReadMuster<> TestMuster THEN Result:=False;

          Dec(lBytesToRead, lReadCount);

          Application.ProcessMessages;
        END;
      END;
    FINALLY
      DateiStream.Free;
    END;
  EXCEPT
    Result:=False;
  END;
END;

Muetze1 17. Jun 2008 15:59

Re: StreamWrite erzeugt nur 0 Byte-File
 
Du lässt dir auch deinen Stack überschreiben. Es wurde zuvor explizit das erste Zeichen bei Strings angegeben - aus gutem Grund. Du machst dies nicht und übergibst damit die Adresse der Stringvariablen auf deinem Stack und lässt dir diesen mit den Dateidaten vollkippen.

Und nochwas: Wenn du den String auf eine Länge bzw. Grösse von 64 Bytes setzt um ihn dann wieder auf eine Länge von 0 (Leerstring) zurück zu setzen, macht irgendwie, wenn man dies so liest in diesem Satz, wenig Sinn. Weil im Endeffekt hast du dann wieder 0 Bytes für deine Dateidaten.

BTW: Schonmal aufgefallen, dass deine Funktion niemals True zurück gibt und du eigentlich sogar einen Hinweis von dem Compiler bekommst, dass der Rückgabewert der Funktion undefiniert sein könnte?

DevidEspenschied 17. Jun 2008 16:11

Re: StreamWrite erzeugt nur 0 Byte-File
 
Zitat:

Zitat von Muetze1
Du lässt dir auch deinen Stack überschreiben. Es wurde zuvor explizit das erste Zeichen bei Strings angegeben - aus gutem Grund. Du machst dies nicht und übergibst damit die Adresse der Stringvariablen auf deinem Stack und lässt dir diesen mit den Dateidaten vollkippen.

Und nochwas: Wenn du den String auf eine Länge bzw. Grösse von 64 Bytes setzt um ihn dann wieder auf eine Länge von 0 (Leerstring) zurück zu setzen, macht irgendwie, wenn man dies so liest in diesem Satz, wenig Sinn. Weil im Endeffekt hast du dann wieder 0 Bytes für deine Dateidaten.

In der Hilfe wird der Rückgabepuffer mit "var Buffer;" deklariert, woraus ich schließe, dass es sich auch um einen String handeln kann. Ich hatte davor mit BlockRead gearbeitet und konnte eben genau 64 Byte einlesen. Hier scheint das komplizierter zu sein.

Wenn ich die brisante Zeile entferne, in welcher der String wieder auf '' gesetzt wird, dann wird tatsächlich etwas ausgelesen. Allerdings nur ca. 35 Zeichen von 64 Zeichen, obwohl lReadCount mit der Min-Berechnung auf 64 Byte festgelegt wird.

Zitat:

Zitat von Muetze1
BTW: Schonmal aufgefallen, dass deine Funktion niemals True zurück gibt und du eigentlich sogar einen Hinweis von dem Compiler bekommst, dass der Rückgabewert der Funktion undefiniert sein könnte?

Ja, vor dem ersten Try-Wort wird Result:=True gesetzt. Das ist hier irgendwie untergegangen.

Muetze1 17. Jun 2008 16:14

Re: StreamWrite erzeugt nur 0 Byte-File
 
Zitat:

Zitat von devidespe
In der Hilfe wird der Rückgabepuffer mit "var Buffer;" deklariert, woraus ich schließe, dass es sich auch um einen String handeln kann. Ich hatte davor mit BlockRead gearbeitet und konnte eben genau 64 Byte einlesen. Hier scheint das komplizierter zu sein.

Achtung! Das ist ein typenloser Parameter und die Strings sind mit Referenzzählung versehen. Diese Analogie kann man nicht so einfach schliessen.

Schonmal mit der Angabe des erstens Zeichens probiert?


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:02 Uhr.
Seite 3 von 4     123 4      

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