Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Simultaner Zugriff auf Datei (https://www.delphipraxis.net/180572-simultaner-zugriff-auf-datei.html)

kkoe 30. Mai 2014 16:26

Simultaner Zugriff auf Datei
 
Hallo zusammen,

ich programmiere erst seit kurzem mit Delphi und habe ein Problem, was ich bisher nicht im Netz, in Foren oder sonstigem beschrieben gefunden habe. (Und dennoch scheint es mir ein häufig vorkommendes Problem zu sein ;))

Das Problem: ich habe zwei Programme, die beide auf eine Datei zugreifen sollen (das eine schreibt Daten hinein, das andere liest diese). Das ganze geschieht zyklisch, aber nicht in festen Zeitabständen, sodass das Lese-Programm (welches ich nur beeinflussen kann) alle X-Millisekunden den Zeitstempel der Datei auf eine Aktualisierung überprüft und dann mit dem Auslesen beginnen würde. Bei der Abfrage des Zeitstempels kann/kommt es z.T. zu gleichzeitigem Zugriff beider Programme auf die Datei, was zum Programmabsturz führt.

Ich hatte versucht, das Lesen des Zeitstempels über try...except abzufangen, funktioniert aber nicht. Gibt es in Delphi andere Möglichkeiten, dieses Problem zu umgehen, ohne beide Programme von außen schedulen zu müssen??
Mir würde es zudem genügen, wenn sich das Lese-Programm "devot" verhält, d.h. seinen Zugriff auf die Datei nicht einfordert, sondern einfach wartet, bis das Schreibe-Programm fertig ist.


Vielen Dank schon einmal!

Bjoerk 30. Mai 2014 17:04

AW: Simultaner Zugriff auf Datei
 
Rewrite öffnet die Datei exclusiv. Währenddessen in eine zweites Rewrite nicht möglich. (Nur) das muß man abfangen, dem Reset ist es egal.

himitsu 30. Mai 2014 19:22

AW: Simultaner Zugriff auf Datei
 
Grundsätzlich können alle Rechte gewehrt/gesperrt werden.

Beim Zugriff auf eine Datei muß man angeben was man für Recht haben muß (Lesen und/oder Schreiben) und dabei kann man auch angeben welche weiteren Zugriffe gleichzeitig erlaubt sind, egal ob von fremden Programmen oder vom Eigenem.
Ist die Datei bereits geöffnet, dann muß der gewünschte Zugriff vom Anderen erlaubt sein.

Die alten Dateifunktionen gewähren nur gleichzeitige Lesezugriffe und es gibt keine (praktikable) Möglichkeit das zu beeinflussen.
Vom RTL-Code her sah es jetzt zwar so aus, als wenn immer Lesezugriffe gewehrt weren, aber beim Schreiben verbiete ich (standardmäßig) selber auch fast immer alle weiteren Zugriffe und beim Lesen verbiete ich Anderen das Schreiben, um konsistente Daten zu gewährleisten. Also wenn das die RTL doch genauso macht und ich es jetzt nur falsch sah, dann würde ich das Verhalten dennoch als richtig betrachten.


Fazit: Dein Programm muß die Zugriffe des anderen Programms gewährleisten und theoretisch könntest du die Datei sogar die ganze Zeit offen lassen.
Aber wenn das andere Programm deine Zugriffe beim Lesen verbietet, dann wirst du damit leben müssen, da du das ja nicht beeinflussen kannst.

kkoe 2. Jun 2014 16:31

AW: Simultaner Zugriff auf Datei
 
Danke Euch beiden, das hat schon mal Hilfe in die richtige Richtung gegeben. Was ich vergessen hatte zu erwähnen, ist dass die Schnittstellen Datei ein XML File ist, und "Rewrite", so schön einfach dieser Ansatz auch aussah, nach meiner Recherche nur bei Textfiles funktioniert?!

Aber ich denke, ich suche genau die Exklusivrechte beim Öffnen einer Datei, die Ihr angesprochen habt. Habe dazu ein kleines Beispiel programmiert, wobei mir diese Exclusivrechte sofort selber auf die Füße gefallen sind. Vlt seht ihr den Fehler.

Delphi-Quellcode:
// Beispiel XML erstellen
procedure TForm1.Button2Click(Sender: TObject);
var
root, c1: IXMLNode;
begin
 count:=0;
 fn:='C:\Temp\Test.xml';
 xml:=TXMLDocument.Create(self);
 xml.Active:=true;
 xml.Version:='1.0';
 xml.Encoding:='UTF-8';
 xml.StandAlone:='no';
 root:=xml.AddChild('ErsterKnoten');
 c1:=root.AddChild('ZweiterKnoten');
 c1.Text:='1';
 xml.XML.Text := FormatXMLData(xml.XML.Text);
 xml.Active:=true;
 xml.SaveToFile(fn);
 xml.Free;
end;

// Timer starten (weil später auch zyklischer Prozess)
procedure TForm1.Button1Click(Sender: TObject);
begin
 Timer1.Enabled:=true;
end;



procedure TForm1.Timer1Timer(Sender: TObject);
begin
 inc(count);
 // Öffnen der zuvor erstellten Datei unter Exklusivrechten
 temp:=FileOpen(fn, fmOpenReadWrite or fmShareExclusive);

 if temp <> -1 then begin

  //hier soll die Datei jetzt bearbeitet werden
 
  xml:=TXMLDocument.Create(self);
  xml.LoadFromFile('C:\Temp\Test.xml');
  xml.ChildNodes.Nodes[1].ChildNodes.Nodes[0].Text:=IntToStr(count);
  Label1.Caption:='Neuer Wert: '+IntToStr(count);
  xml.SaveToFile('C:\Temp\Test.xml');
  xml.Free;
  temp
  FileClose(temp);
 end
 else begin
  Timer1.Enabled:=false;
  ShowMessage('Datei konnte nicht geladen werden');
 end;

end;

end.


Die Fehlermeldung lautet: Datei wird schon von einem anderen Prozess benutzt...
Das Problem liegt wohl darin, dass ich mit LoadfromFile das XML nochmal versuche zu öffnen... aber wie sonst könnte man das XML anderweitig bearbeiten? Danke im Voraus!

himitsu 2. Jun 2014 16:43

AW: Simultaner Zugriff auf Datei
 
Zitat:

Zitat von OH: fmshareexclusive
Legt eine gemeinsame Dateinutzung fest, die jeglichen Dateizugriff durch andere Anwendungen verhindert.

:roll:

Zitat:

Delphi-Quellcode:
xml.LoadFromFile('C:\Temp\Test.xml');

Das Problem liegt wohl darin, dass ich mit LoadfromFile das XML nochmal versuche zu öffnen...
Nicht nur vermutlich, sondern bestimmt.

Die Datei nicht exklusiv öffnen, den String auslesen
und dann den XML-"String" an die XML-Komponente übergeben.

Genauso kann man den XML-String erst aus der Komponente rausholen und dann selber in die Datei schreiben.

kkoe 2. Jun 2014 17:02

AW: Simultaner Zugriff auf Datei
 
Zitat:

Die Datei nicht exklusiv öffnen, den String auslesen
und dann den XML-"String" an die XML-Komponente übergeben.
Jetzt komm ich nicht mit, welcher ist der String und welcher der XML-"String"(=Filename??)?
Und durch das Weglassen der Exklusivrechte können doch wieder andere Programme auf die Datei zugreifen, während dieses Programm am bearbeiten ist, oder? (Das wollte ich ja verhindern)

Der schöne Günther 2. Jun 2014 17:46

AW: Simultaner Zugriff auf Datei
 
Entweder habe ich gravierende Wissenslücken oder, soweit wir hier fest bei Windows sind, macht keiner eine Datei zum Lesen auf wenn da grade reingeschrieben wird. Nicht einmal der gleiche Prozess.
Willst du die Datei ein weiteres mal (zum Lesen) aufmachen muss der Schreibende entweder ein Mapping für die Datei angelegt haben (siehe MSDN: Sharing Files and Memory) oder der lesende ist ein Kindprozess des Schreibenden und kann das Filehandle erben.

Ansonsten, kein Weg. Das hätte ich jetzt spontan behauptet. Wenn das nicht stimmt freue ich mich :wink:

Bjoerk 2. Jun 2014 18:03

AW: Simultaner Zugriff auf Datei
 
Ich hab' mal ne Zeitlang das verwendet, dann aber wieder verworfen. Weiß aber nicht mehr warum?
Delphi-Quellcode:
function FileInUse(const FileName: string): boolean;
var
  Success: Cardinal;
begin
  Result := false;
  if FileExists(FileName) then
  begin
    Success := CreateFile(PChar(FileName),
      GENERIC_READ, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    Result := Success = INVALID_HANDLE_VALUE;
    if not Result then
      CloseHandle(Success);
  end;
end;

procedure Wait50;
var
  ATime: Cardinal;
begin
  ATime := GetTickCount;
  repeat
  until GetTickCount - ATime > 50;
  Application.ProcessMessages;
end;

function CanOpenFile(const FileName: string): boolean;
var
  TryCount: integer;
begin
  Result := true;
  if FileInUse(FileName) then
  begin
    TryCount := 0;
    repeat
      Wait50;
      Inc(TryCount);
      Result := not FileInUse(FileName);
    until Result or (TryCount = 20);
  end;
  if not Result then
    MessageDlg('Zugriff auf ' + FileName + ' verweigert.', mtError, [mbOK], 0);
end;

Der schöne Günther 2. Jun 2014 18:08

AW: Simultaner Zugriff auf Datei
 
Das versucht ja nur, mittels
Delphi-Quellcode:
CreateFile
die Datei zum Lesen aufzumachen und sagt, ob dabei
Delphi-Quellcode:
INVALID_HANDLE_VALUE
herauskam oder nicht. Auf so eine Lösung wird es denke ich ja auch hinauslaufen-

Nur würde ich hierbei bemängeln dass die Wahrscheinlichkeit zwar wahrscheinlich hoch, aber nicht garantiert ist dass du deine öffnen kannst nachdem das Prüfen einmal meinte, man könne sie zum Lesen öffnen: Zwischen Prüfen und Aufmachen kann sie sich ja schon wieder jemand anders geschnappt haben- Die Gegenseite könnte beispielsweise wieder anfangen zu schreiben.

Bjoerk 2. Jun 2014 18:24

AW: Simultaner Zugriff auf Datei
 
Kann sein. Prüfte glaub ich GENERIC_READ or GENERIC_WRITE usw. Weiß nicht mehr so genau?

EarlyBird 2. Jun 2014 18:56

AW: Simultaner Zugriff auf Datei
 
Eventuell kannst Du die Datei auch kopieren und nach dem Lesen löscht du die Datei wieder.

samso 3. Jun 2014 07:16

AW: Simultaner Zugriff auf Datei
 
Liste der Anhänge anzeigen (Anzahl: 1)
Irgendwie verstehe ich die Diskussion nicht. Selbstverständlich kann man eine Datei zum Lesen öffnen, auch wenn sie gerade geschrieben wird. Es können sogar mehrere Prozesse die Datei zum Schreiben öffnen. Dazu muss man TFilestreams mit den korrekten Parametern erzeugen und schon geht das wunderbar.
Zusätzlich sollte man sich einen Transaktions-Mechanismus ausdenken, der sicher stellt, dass die Daten konsistent sind. Aber das war ja hier nicht gefragt. Natürlich darf die Datei von keinem Prozess mit Exklusiv-Rechten geöffnet sein.

Anbei habe ich eine kleine Demo erzeugt. Dieses Programm kann mehrmals gestartet werden und alle können fröhlich auf der Datei schreiben und lesen.
Hinweis: Bei Delphis älter als Delphi 2010 (vielleicht auch 2009?) hat fmCreate noch keinen Share-Parameter erlaubt. Deshalb gibt es im Demo einen etwas wirren Workaround dafür. D.h. Wenn die Datei noch nicht existiert wird die Datei erzeugt und danach nochmal geschlossen. Ab Delphi 2010 kann man sich das sparen.

Dejan Vu 3. Jun 2014 07:32

AW: Simultaner Zugriff auf Datei
 
Wenn ich eine Datei lesen will, die von einem anderen Prozess blockiert wird, kopiere ich mir die Datei und öffne die Kopie. Das klappt fast immer (außer bei SQL-Server).

Der schöne Günther 3. Jun 2014 08:00

AW: Simultaner Zugriff auf Datei
 
Zitat:

Zitat von samso (Beitrag 1261123)
Selbstverständlich kann man eine Datei zum Lesen öffnen, auch wenn sie gerade geschrieben wird. Es können sogar mehrere Prozesse die Datei zum Schreiben öffnen. [...] Natürlich darf die Datei von keinem Prozess mit Exklusiv-Rechten geöffnet sein. Anbei habe ich eine kleine Demo erzeugt.

Du hast vollkommen recht, keine Ahnung warum ich gestern so einen Humbug erzählt habe :oops:

Die Dokumentation zu TFileStream.Create(..) fand ich (vor allem in der deutschen Fassung) auch nicht grade einfach verständlich. Aber wahrscheinlich sind's die Viren in meinem Kopf :vernupft:


Gutes Beispiel. :)

samso 3. Jun 2014 08:08

AW: Simultaner Zugriff auf Datei
 
Aha, dieser Nebensatz scheint entscheidend zu sein.
Zitat:

Zitat von kkoe (Beitrag 1261074)
Und durch das Weglassen der Exklusivrechte können doch wieder andere Programme auf die Datei zugreifen, während dieses Programm am bearbeiten ist, oder? (Das wollte ich ja verhindern)

Der TE will vermutlich durch das exklusive öffnen der Datei den Transaktions-Mechanismus realisieren? Aus den anderen Nebenbemerkungen schließe ich, das die Datei in relativ kurzen Zeitabständen aktualisiert wird (da ist von ms die Rede). In einem solchen Fall würde ich denken, dass das besser über einen Masterprozess realisiert wird, der dann die Daten nach außen via Interprozesskommunikation zu Verfügung stellt.

himitsu 3. Jun 2014 08:12

AW: Simultaner Zugriff auf Datei
 
Zitat:

Zitat von Dejan Vu (Beitrag 1261126)
Wenn ich eine Datei lesen will, die von einem anderen Prozess blockiert wird, kopiere ich mir die Datei und öffne die Kopie.

Wenn du die Datei kopieren kannst, dan gibt das andere Program dir das echt die Datei zu lesen und dann kann man die Datei auch direkt öffnen.

Wenn des andere Programm keine Leserchte gewährt, dann kann man die Datei weder lesen noch kopieren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:44 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