AGB  ·  Datenschutz  ·  Impressum  







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

StreamWrite erzeugt nur 0 Byte-File

Ein Thema von little_budda · begonnen am 5. Jun 2008 · letzter Beitrag vom 18. Jun 2008
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    
Benutzerbild von little_budda
little_budda

Registriert seit: 5. Mai 2006
Ort: Velbert
246 Beiträge
 
Delphi 2006 Professional
 
#1

StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 09:13
Hallo,

ich nutze folgende Code um eine binäre Datei zu erzeugen.
Delphi-Quellcode:
procedure Tfrm_main.Button1Click(Sender: TObject);
var aFileBuffer : array of byte;
    iFileLength, ix, iByteCounter : integer;
    datei : tfilestream;
    bStreamOk : boolean;
    s_filename, startpfad : string;
begin
  iFileLength := strtoint(edit1.text); // Aktueller Wert: '20980826'
  // Array erzeugen
  setLength(aFileBuffer, iFileLength);

  for ix := 0 to (iFileLength - 1)
    do aFileBuffer[ix] := 55;

  // Startpfad ermitteln
  getdir(0, startpfad); // Startpfad einlesen
  if (startpfad[length(startpfad)] <> '\')
    then startpfad := startpfad + '\'; // Pfad ggf. korrigieren

  // Dateiname zuweisen
  s_filename := startpfad + edit2.Text; // Aktueller Wert: 'data.bin'

  bStreamOk := true;
  try
    datei := Tfilestream.create(s_filename, fmcreate or fmShareExclusive);
  except
    bStreamOk := false;
  end;

  if (bStreamOk = true) then
    begin
      // Schreiben der DateiInhalte in den Stream
      try
        iByteCounter := datei.Write(aFileBuffer, iFileLength);
      finally
        datei.free;
      end;
      // Prüfen ob die korrekte Anzahl Bytes geschrieben wurde
      if (iByteCounter <> iFileLength)
        then showmessage('Stream wurde erzeugt, hat aber die falsche Größe.')
        else showmessage('Stream wurde erzeugt.');
    end
  else
    begin
      showmessage('Stream konnte nicht erzeugt werden.');
    end;
end;
Leider wird die Datei aber immer nur nit einer Länge von 0 Byte angelegt.
Was bitte mache ich denn falsch?

Gruß Holger.

Holger
Glück findet sich nicht im Code
Gefahren werden ist nur solange schön wie man selbst nicht lenken möchte ...
  Mit Zitat antworten Zitat
mkinzler
(Moderator)

Registriert seit: 9. Dez 2005
Ort: Heilbronn
39.851 Beiträge
 
Delphi 11 Alexandria
 
#2

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 09:17
iByteCounter := datei.WriteBuffer(aFileBuffer, iFileLength); Statt
if (bStreamOk = true) then besser
if bStreamOk then
Markus Kinzler
  Mit Zitat antworten Zitat
Benutzerbild von little_budda
little_budda

Registriert seit: 5. Mai 2006
Ort: Velbert
246 Beiträge
 
Delphi 2006 Professional
 
#3

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 09:21
Danke
Holger
Glück findet sich nicht im Code
Gefahren werden ist nur solange schön wie man selbst nicht lenken möchte ...
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#4

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 09:30
Hallo little Budda,

Ich habe Deinen Code einmal ausprobiert und leicht geändert:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var aFileBuffer : array of byte;
    iFileLength, ix, iByteCounter : integer;
    datei : tfilestream;
    bStreamOk : boolean;
    s_filename, startpfad : string;
begin
  [b]iFileLength := 123; // Aktueller Wert: '20980826'[/b]
  // Array erzeugen
  setLength(aFileBuffer, iFileLength);

  for ix := 0 to (iFileLength - 1)
    do aFileBuffer[ix] := 55;

  // Startpfad ermitteln
  getdir(0, startpfad); // Startpfad einlesen
  if (startpfad[length(startpfad)] <> '\')
    then startpfad := startpfad + '\'; // Pfad ggf. korrigieren

  // Dateiname zuweisen
 [b] s_filename := 'c:\temp\test.bin'; // Aktueller Wert: 'data.bin'[/b]
  bStreamOk := true;
  try
    datei := Tfilestream.create(s_filename, fmcreate or fmShareExclusive);
  except
    bStreamOk := false;
  end;

  if (bStreamOk = true) then
    begin
      // Schreiben der DateiInhalte in den Stream
      try
        iByteCounter := datei.Write(aFileBuffer, iFileLength);
      finally
        datei.free;
      end;
      // Prüfen ob die korrekte Anzahl Bytes geschrieben wurde
      if (iByteCounter <> iFileLength)
        then showmessage('Stream wurde erzeugt, hat aber die falsche Größe.')
        else showmessage('Stream wurde erzeugt.');
    end
  else
    begin
      showmessage('Stream konnte nicht erzeugt werden.');
    end;
end;
und siehe da es wird eine 123Byte große Datei erzeugt.
Schau Dir im Debugger die Übergabe der Dateigröße einmal an.

Gruß
K-H
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#5

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 09:42
Also irgendwie sieht euer Code komisch aus.

Dieses bStreamOK stört mich zum Beispiel. Das kann man doch so lösen:;
Delphi-Quellcode:
datei := TFileStream.Create(...);
if Assigned(datei) then
begin
  try
    try
      BytesWritten := datei.Write(...);

    except
      raise Exception....
  finally
    datei.Free;
  end;
end;
Desweiteren würde ich die Daten/Code von der Oberfläche trennen, also den Code in eine separate Methode auslagern, die von der Schaltfläche aufgerufen wird:
Delphi-Quellcode:
procedure Tfrm_main.Button1Click(Sender: TObject);
begin
  try
    SchreibeDatei(...);
  except
    on E: Exception do ShowMessage(E.Message);
  end;
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Muetze1
(Gast)

n/a Beiträge
 
#6

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 09:47
GetDir(0, x); ist eine schlechte Wahl, da es der aktuelle Pfad ist und dieser somit nicht zwingend der "Startpfad" ist. Ein Open/SaveDialog z.B. ändern diesen Standardpfad standardmässig mit den Nutzeraktionen. Hier solltest du lieber auf ParamStr(0) zurück greifen.

Auch ist dein Test auf ein abschließenden Backslash eine Fehlerquelle, wenn der string mal leer ist. Dann würde es zu einer Zugriffsverletzung bzw. einem Range Check Error kommen. Nutze lieber dazu die von der VCL definierten Funktion IncludeTrailingPathDelimiter().

Deine Prüfung ob die Erstellung der TFileStream Instanz erfolgreich war, könnte man noch in zwei Dingen ändern/verbessern: Zum einen würde eine Exception aus dem Constructor die Instanzenvariable niemals zuweisen, da er durch die Exception diesen Coder erst gar nicht mehr ausführt. Von daher kannst du auch einfach die Instanzenvariable auf NIL setzen vor dem try und dann danach abprüfen, ob diese ungleich nil ist.
Und zum anderen kann der Constructor nur durch eine Exception abgebrochen werden und somit kannst du auch einfach den Except Block hinter deine Dateiroutinen verschieben, weil durch die Exception würde er diese nicht mehr ausführen und am Ende gefangen werden.

/EDIT: Toll, alle schreiben während ich hier tippe.

@Luckie: Du musst explizit datei auf nil setzen, weil es eine (nicht initialisierte) lokale Variable ist. Und wenn, ein Constructor gibt niemals nil zurück, sondern wird höchstens mit einer Exception abgebrochen und damit würde deine Abfrage erst gar nicht mehr zum Zuge kommen.
Und warum mit Except eine Exception fangen um dann eine eigene zu werfen? Warum willst du die zusätzlichen Informationen der originalen Exception wegwerfen? Warum eine unspezifizierte eigene Exception? Wenn, dann wieder re-raisen mit raise, aber dann brauchste auch kein Except Block, den kannst du dir dann auch gleich sparen.
Und es fehlt ein end; bei deinem Code...

@p80286: Wie schon erwähnt, würde ich den Vergleich auf true unbedingt abändern!
  Mit Zitat antworten Zitat
Benutzerbild von Luckie
Luckie

Registriert seit: 29. Mai 2002
37.621 Beiträge
 
Delphi 2006 Professional
 
#7

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 09:50
Zitat von Muetze1:
@Luckie: Du musst explizit datei auf nil setzen, weil es eine (nicht initialisierte) lokale Variable ist. Und wenn, ein Constructor gibt niemals nil zurück, sondern wird höchstens mit einer Exception abgebrochen und damit würde deine Abfrage erst gar nicht mehr zum Zuge kommen.
Und warum mit Except eine Exception fangen um dann eine eigene zu werfen? Warum willst du die zusätzlichen Informationen der originalen Exception wegwerfen? Warum eine unspezifizierte eigene Exception? Wenn, dann wieder re-raisen mit raise, aber dann brauchste auch kein Except Block, den kannst du dir dann auch gleich sparen.
Und es fehlt ein end; bei deinem Code...
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?
Michael
Ein Teil meines Codes würde euch verunsichern.
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#8

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 10:02
Hallo Little Budda,

sorry ich hab mich etwas vergallopiert, Aus mir unerfindlichen Gründen ist bei der Dateigröße von $3AEC (ca 15 000) Schluß mit lustig. Da liegt das Problem weniger in Deinem Code als irgendwo anders.

Gruß
K-H
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#9

Re: StreamWrite erzeugt nur 0 Byte-File

  Alt 5. Jun 2008, 10:05
@Muetze

Naja halte ich für Geschmackssache. Deine Version gefällt mir besser aber ist sie darum richtiger. Ist schließlich little Buddas Code und er muß sich darin zurechtfinden.

Gruß
K-H
  Mit Zitat antworten Zitat
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
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    


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 21:37 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