Entwickler-Ecke

Dateizugriff - Filecreate: Datei wird nach dem Erzeugen nicht beschrieben.


bf109g.01 - Mi 23.03.11 00:18
Titel: Filecreate: Datei wird nach dem Erzeugen nicht beschrieben.
Hallo, ich benutze für mein Programm eine INI-Datei.
Nun habe ich folgendes Problem.

- Beim Programmstart soll die INI ausgelesen werden.
- Ist keine vorhanden, soll eine erzeugt, mit Standardwerten beschrieben und abgespeichert werden.
- Die Datei wird zwar erzeugt, ist danach aber immer leer. Erst wenn man das gesamte Programm neustartet, funktioniert das GAnze.

Was muss ich da jetzt bitte ändern?


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
type Spieler= record
              Name   : string[15];
              color: Tcolor;
              Games: Integer;
              end;
Speicherfeld=array [1..3of Spieler;
var
  Speicher       : Speicherfeld;
  Player1, Player2, AllgPlayer: Spieler;
// --------------------------------------------------------------
procedure TForm_Spiel.StartDaten_einlesen;
var Save: File of Speicherfeld;
    path: string;
begin
  path:=ExtractFilePath(ParamStr(0))+'\config.ini';
  if not fileexists(path) then
    begin
      Filecreate('config.ini');
      MessageDlg('File "config.ini" can not be found.', mtError, [mbok], 0);
      Standardsettings;
      Spiel_Speichern;
    end
  else
    begin
      AssignFile(Save,Path);
      Reset(Save);
        read(Save,Speicher);
      CloseFile(Save);

      Player1:=Speicher[1];
      Player2:=Speicher[2];
      AllgPlayer:=Speicher[3];
    end;

  En1.Text:=Player1.name;
  En2.Text:=Player2.name;
  Pf1.color:=Player1.color;
  Pf2.color:=Player2.color;
end;

procedure TForm_Spiel.Standardsettings;
begin
  Player1.name:='Player 1';
  Player1.color:=clred;
  Player2.name:='Player 2';
  Player2.color:=clblue;
  AllgPlayer.Games:=0;
end;

procedure TForm_Spiel.Spiel_Speichern;
var Save: File of Speicherfeld;
    path: string;
begin
  Speicher[1]:=Player1;
  Speicher[2]:=Player2;
  Speicher[3]:=AllgPlayer;

  path:=ExtractFilePath(ParamStr(0))+'\config.ini';

  AssignFile(Save,path);
  Rewrite(Save);
    write(Save,Speicher); // "E/A-Fehler 32" an dieser Stelle wird eben in die neue Datei nicht hineingeschrieben
  CloseFile(Save);
end;


Gerd Kayser - Mi 23.03.11 01:16

E/A-Fehler 32 = "The process cannot access the file because it is being used by another process." Siehe: http://msdn.microsoft.com/en-us/library/ms681382(VS.85).aspx
So wie ich das sehe, wird nach dem FileCreate die Datei nicht geschlossen. Wenn Du dann versuchst, die Datei nochmals zu öffnen, knallt es.
Warum wertest Du nicht die Rückgabewerte der Funktionen aus?
Auszug aus der Hilfe zu FileClose: "Mit FileClose kann eine Datei anhand ihres Handles geschlossen werden. Sie erhalten das Handle beim Öffnen der Datei mit FileOpen oder FileCreate."


jaenicke - Mi 23.03.11 07:13

Du kannst die Hilfe auch einfach verlinken. ;-)
http://docwiki.embarcadero.com/VCL/de/SysUtils.FileClose


jasocul - Mi 23.03.11 09:14

Das CreateFile ist überflüssig und die Ursache des Fehlers.
Rewrite sorgt schon dafür, dass die Datei angelegt wird, falls diese nicht existiert.

btw:
Das ist keine INI-Datei, sondern eine typisierte Datei. :wink:


bf109g.01 - Mi 23.03.11 18:37

user profile iconjasocul hat folgendes geschrieben Zum zitierten Posting springen:
btw:
Das ist keine INI-Datei, sondern eine typisierte Datei. :wink:
Dann wäre es doch auch sehr geistreich, die Datei nicht als *.ini anzulegen, denke ich.
Welchen Typ nimmt man dann standardmäßig stattdessen? *.dat?

Werde jetzt einfach mal das Filecreate rausschmeißen und schauen, was geschieht. :)


jaenicke - Mi 23.03.11 18:41

user profile iconbf109g.01 hat folgendes geschrieben Zum zitierten Posting springen:
Welchen Typ nimmt man dann standardmäßig stattdessen? *.dat?
Die Endung gibt es schon in Windows selbst, ich würde z.B. .gameconfig oder so etwas nehmen.


Gerd Kayser - Mi 23.03.11 18:48

Zitat:
Dann wäre es doch auch sehr geistreich, die Datei nicht als *.ini anzulegen, denke ich.
Warum nimmst Du nicht TIniFile (Unit IniFiles)? Wie ich sehe, hast du doch nur Strings und Zahlen zu speichern. Auch Color ist nix anderes als eine Zahl.


jaenicke - Mi 23.03.11 19:12

Besser ist dann TMemIniFile (wenn schon INIs benutzt werden). Denn TIniFile benutzt die alten Windows API Routinen aus der 16-Bit Zeit vor 20 Jahren (woher ja auch INIs stammen). Die sind erstens als deprecated markiert und dementsprechend vielleicht z.B. in Windows 8 schon nicht mehr da und zweitens musste ich feststellen, dass die auch nicht immer wie gewünscht arbeiten.

TMemIniFile benutzt eigene Implementierungen (zumindest unter Delphi XE) und arbeitet korrekt.

Davon abgesehen würde ich eher XML-Dateien nehmen, zum Beispiel mit meiner entsprechenden Unit, die das alles kapselt:
http://www.delphi-forum.de/viewtopic.php?t=92348


Gerd Kayser - Mi 23.03.11 20:22

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Besser ist dann TMemIniFile (wenn schon INIs benutzt werden). Denn TIniFile benutzt die alten Windows API Routinen aus der 16-Bit Zeit vor 20 Jahren (woher ja auch INIs stammen). Die sind erstens als deprecated markiert und dementsprechend vielleicht z.B. in Windows 8 schon nicht mehr da und zweitens musste ich feststellen, dass die auch nicht immer wie gewünscht arbeiten.
Weder in der XE-Hilfe ms-help://embarcadero.rs_xe/vcl/IniFiles.TCustomIniFile.ReadInteger.html noch bei http://docwiki.embarcadero.com/VCL/de/IniFiles.TIniFile.ReadString ist ein entsprechender Hinweis zu finden. Ich arbeite hier problemlos mit IniFiles unter XE und Windows 32. Außerdem hat TMemInifile gegenüber TIniFile den Nachteil, daß die Schreibzugriffe gecached werden.
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Davon abgesehen würde ich eher XML-Dateien nehmen
Ich hasse die Dinger ...


jaenicke - Mi 23.03.11 20:37

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:
Weder in der XE-Hilfe ms-help://embarcadero.rs_xe/vcl/IniFiles.TCustomIniFile.ReadInteger.html noch bei http://docwiki.embarcadero.com/VCL/de/IniFiles.TIniFile.ReadString ist ein entsprechender Hinweis zu finden.
Dort nicht, aber bei den API-Funktionen, die diese Methoden benutzen. Und wenn die nicht mehr funktionieren irgendwann, funktionieren logischerweise auch alle Programme, die diese Funktionen nutzen, nicht mehr.
http://msdn.microsoft.com/en-us/library/ms724353(v=vs.85).aspx hat folgendes geschrieben:
Note This function is provided only for compatibility with 16-bit Windows-based applications.


Gerd Kayser - Do 24.03.11 01:04

user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Dort nicht, aber bei den API-Funktionen, die diese Methoden benutzen. Und wenn die nicht mehr funktionieren irgendwann,[...]
Bis dahin wird noch sehr viel Wasser den Main hinunter fließen ...


jaenicke - Do 24.03.11 06:50

user profile iconGerd Kayser hat folgendes geschrieben Zum zitierten Posting springen:
Bis dahin wird noch sehr viel Wasser den Main hinunter fließen ...
Vermutlich, aber wissen kann man das nicht. Schließlich sind bei 64-Bit Systemen diese Funktionen nicht mehr notwendig, da 16-Bit Programme ohnehin nicht mehr funktionieren. Sobald es also keine 32-Bit Version von Windows mehr gibt, macht es auch keinen Sinn mehr diese Funktionen zu behalten.

Davon abgesehen gibt es schließlich eine Alternative, die nicht auf diesen API Funktionen aufsetzt. Zudem einmal als Beispiel:

Quelltext
1:
2:
[Test]
a="Test","Nichts"
Was kommt bei ReadString wohl heraus?
Bei TIniFile: Test","Nichts
Bei TMemIniFile: "Test","Nichts"
Das ist nur eines der Probleme, die TIniFile bei mir bereits gemacht hat...