Avatar billede kennethv Nybegynder
21. maj 2005 - 10:19 Der er 25 kommentarer og
1 løsning

Vente med at åbne en fil før den er lukket.

Et andet program opretter en fil med nogle oplysninger i som jeg skal bruge. Men jeg vil vente med at åbne filen før det andet program er færdig med at skrive i filen og har lukket den dvs, at programmet ikke har fat i den mere. Er det muligt og hvad skal jeg se efter?
Avatar billede doc404 Novice
21. maj 2005 - 12:34 #1
Hvordan læser du normalt fra filen?
Avatar billede kennethv Nybegynder
21. maj 2005 - 13:00 #2
Jeg er ikke kommet så langt, men jeg vil helst bruge noget stilen:

Procedure TForm1.OpenFile;
var FileList : TStringList;
begin
  FileList := TStringList.Create;
  FileList.LoadFormFile(filnavn);
end;
Avatar billede kroning Nybegynder
21. maj 2005 - 14:59 #3
Det andet program er det dig eget lavet program? Hvis det er kunne du evt. fra dette program sende en Message med SendMessage når filen er lukket.
Hvis ikke så kik evt. på FindFirstChangeNotification, WaitForSingleObject og FindNextChangeNotification.
Avatar billede kennethv Nybegynder
22. maj 2005 - 07:22 #4
Det andet program har jeg ikke lavet. Jeg er ved at lave en service som tjekker i et bibliotek, som jeg bestemmer, efter en bestemt extension men skal først åbne den når det andet program er færdig med at skrive i den. Kan du give et eksempel på hvordan man bruger dem du har nævnt?
Avatar billede doc404 Novice
22. maj 2005 - 10:40 #5
Det er lidt problematisk...

Du kan åbne filen exclusive, så ingen andre får læse eller skrive adgang. Så får du nemlig en exception, hvis andre programmer stadig har filen åben. Men hvad sker der så, hvis det andet program forsøger, at skrive i filen mens du har låst den? Kan du havne i den situation?

Du har ikke en chance for, at vide hvornår det andet program er færdig med, at skrive - med mindre filen er låst - enten exclusive eller blot for skrivning.

Hvis filen blot bliver oprettet kan du forsøge følgende:

function GetData(const FileName : string) : boolean;
var
  fs : TFileStream;
begin
  try
    fs := TFileStream(FileName,fmOpenRead or fmShareExclusive);
    try
      FileList.LoadFromStream(fs);
      Result := True;
    finally
      FreeAndNil(fs);
    end;
  except
    Result := False; // Filen var låst - prøv igen om lidt
  end;
end;
Avatar billede doc404 Novice
22. maj 2005 - 10:41 #6
Retter lige lidt ;-)

function GetData(const FileName : string) : boolean;
var
  fs : TFileStream;
begin
  try
    fs := TFileStream.Create(FileName,fmOpenRead or fmShareExclusive);
    try
      FileList.LoadFromStream(fs); // FileList deklareret andetsteds..
      Result := True;
    finally
      FreeAndNil(fs);
    end;
  except
    Result := False; // Filen var låst - prøv igen om lidt
  end;
end;
Avatar billede kroning Nybegynder
22. maj 2005 - 10:43 #7
Ja, smid en TButton og en TMemo på en form. Når der sker en ændring i en fils attribut i den mappe der er defineret så vil der blive skrevet 'Der er sket en ændring' i memoen. Der er andre muligheder end FILE_NOTIFY_CHANGE_ATTRIBUTES, se hjælpen eller spørg igen. Du kan teste ved at gemme f.eks. en tekst fil med f.eks. Notepad i den aktuelle mappe, bemærk at af en eller anden grund så vil du få 2x'Der er sket en ændring' når du gemmer med Notepad eller Wordpad, dette sker ikke hvis du gemmer med f.eks. Delphi eller MS Word.
I stedet for at bruge FILE_NOTIFY_CHANGE_ATTRIBUTES kan du evt. bruge FILE_NOTIFY_CHANGE_LAST_WRITE og så checke dato/tid når du får besked.
-------------------

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    WatchHandle : THandle;
  public
    { Public declarations }
  end;

TWatchThread = class(TThread)
  private
    { Private declarations }
    WatchHandle : THandle;
    Besked : string;
    procedure SendBesked;
  protected
    procedure Execute; override;

  public
    constructor Create(aWatchHandle : THandle);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TWatchThread }

constructor TWatchThread.Create(aWatchHandle : THandle);
begin
  inherited Create(False);
  WatchHandle:=aWatchHandle;
  FreeOnTerminate:=true;
end;

procedure TWatchThread.SendBesked;
begin
  Form1.Memo1.Lines.Add(Besked);
end;

procedure TWatchThread.Execute;
var result : integer;
begin
  Besked:='Thread startet';
  Synchronize(SendBesked);

  while not terminated do
  begin
    result:=WaitForSingleObject(WatchHandle,100);
    if result=WAIT_OBJECT_0 then
    begin
      Besked:='Der er sket en ændring';
      Synchronize(SendBesked);
    if not FindNextChangeNotification(WatchHandle) then
      begin
    Besked:='Fejl i FindNextChangeNotification';
      Synchronize(SendBesked);
        Terminate;
      end;
    end;
end;
end;

{ end TWatchThread }

procedure TForm1.Button1Click(Sender: TObject);
var
  lpPathName : string;
begin
  lpPathName:='c:\hk'; // mappen der skal overvåges
    WatchHandle:=FindFirstChangeNotification(PChar(lpPathName),false,FILE_NOTIFY_CHANGE_ATTRIBUTES);
  if WatchHandle=INVALID_HANDLE_VALUE then
    Memo1.Lines.Add('fejl i FindFirstChangeNotification');

  TWatchThread.Create(WatchHandle);
end;

end.
Avatar billede kennethv Nybegynder
22. maj 2005 - 21:19 #8
Nej, jeg vil ikke komme i den situation at det andet program vil skrive i filen igen, da det vil ske een gang. Jeg vil lige se på jeres eksempler.
Avatar billede kennethv Nybegynder
22. maj 2005 - 23:03 #9
Doc404, vil lige høre om den function du har lavet om den vil kunne bruges til at tjekke om en fil er lukket for at være klar til at åbne den igen. Jeg kan godt se hvad den vil returnere, men som jeg ser det, vil den åbne filen uanset om den er åben eller lukket. Jeg kan ikke begynde at læse filen før den er lukket. Først der kan jeg være sikker på at der ikke bliver skrevet flere oplysninger i filen. Så mit svar ovenover må så være ja, det kan forekomme ud fra den måde du spørger på. Men hvis du spørger mig det andet program vil åbne den samme fil efter, at den har skrevet i den, vil svaret være nej. Navnet på filen vil være forskelligt, men ikke extension. Den vil være det samme.
Avatar billede doc404 Novice
22. maj 2005 - 23:15 #10
Argumentet fmShareExclusive gør at filen skal kunne åbnes UDEN at andre programmer har eller kan få adgang til den. Derfor vil den fejle - og altså ikke åbne filen, hvis et andet program stadig har filen åben.

Filen bliver kun åbnet og data læst, hvis filen er fri.
Avatar billede kennethv Nybegynder
23. maj 2005 - 10:39 #11
Okay!

Denne procedure bliver brugt når der sker en ændring i et bibliotek som jeg bestemmer. Hvordan er det muligt at bruge din function i den? Den skal blive ved med undersøge filen til den er klar også åbne den? Og er der nogen forskel i at bruge FileList.loadfromfile(FileName)? Og er den enten fmOpenRead eller fmShareExclusive man bruger?

procedure TService1.ShellChangeNotifier1Change;
var sr: TSearchRec;
begin
  if findfirst(ShellChangeNotifier1.Root + '*.ilp',faAnyFile,sr) = 0 then 
  begin
    FileName := sr.Name;
  end;
  FindClose(sr);
end;
Avatar billede stoney Nybegynder
23. maj 2005 - 11:27 #12
Kan du ikke bare checke om filen bliver brugt af andre ?

http://www.swissdelphicenter.com/en/showcode.php?id=104

Stoney
Avatar billede kennethv Nybegynder
23. maj 2005 - 12:01 #13
Er det ellers bare at lave:


procedure TService1.ShellChangeNotifier1Change;
var sr: TSearchRec;
begin
  if findfirst(ShellChangeNotifier1.Root + '*.ilp',faAnyFile,sr) = 0 then 
  begin
    FileName := sr.Name;
    repeat
      GetData(FileName)
    until GetData(FileName) = true;
  end;
  FindClose(sr);
end;
Avatar billede kennethv Nybegynder
23. maj 2005 - 21:46 #14
Jeg tror sku at jeg fundet løsningen. Den ligger i den komponent jeg bruger. ShellChangeNotifier. Jeg så mig ikke for. Der er nogle forskellige filter, bl.a en der hedder nfWriteChange := true;

Nu har I gjort et godt stykke arbejde. Jeg aner ikke om de kan det jeg efterlyser og jeg aner ikke hvordan jeg skal fordele de point. Og kan man overhovedet fordele dem?
Avatar billede kroning Nybegynder
23. maj 2005 - 23:34 #15
ShellChangeNotifier benytter nettop FindFirstChangeNotification og FindNextChangeNotification, jeg havde bare glemt alt om at den fandtes.
Avatar billede kennethv Nybegynder
24. maj 2005 - 23:40 #16
Men selvom jeg har har sat det filter og kopiere en fil til det overvåget bibliotek for jeg en "File is being used by another process". Jeg troede at når man satte det filter vil den først se at noget er ændret hvis det filter var sandt.
Avatar billede kennethv Nybegynder
25. august 2005 - 00:08 #17
Kroning: Har du nogen ide til hvordan jeg kan bruge ShellChangeNotifier? Og ellers i det du har lavet, hvordan er det muligt at bruge LogMessage for en service i stedet for at bruge Synchronize(SendBesked);

På forhånd tak.
Avatar billede kroning Nybegynder
25. august 2005 - 09:04 #18
Hvad mener du med LogMessage?
Avatar billede kennethv Nybegynder
25. august 2005 - 09:27 #19
Jeg bruger D2005. Her er en beskrivelse af LogMessage fra onlinedoc.

TService.LogMessage Method

Sends an error message to the event log.

Class
TService

Syntax


[Delphi] public procedure LogMessage(Message: string, EventType: Cardinal, Category: Integer, ID: Integer);


Description
LogMessage sends an error message to the event log when an error or exception occurs. By default the EventType is EVENTLOG_ERROR_TYPE (usually indicating a loss of functionality or data) and the category and ID are zero. For example, if a service cannot be loaded as the system boots, it can log an error event, and the category and ID are zero.

The EventType specifies the type of event being logged. This parameter can be one of the following values:
  Value  Meaning
EVENTLOG_WARNING_TYPE
  Warning event 
EVENTLOG_INFORMATION_TYPE
  Information event 
EVENTLOG_AUDIT_SUCCESS  Success Audit event 
EVENTLOG_AUDIT_FAILURE
  Failure Audit event 

EVENTLOG_ERROR_TYPEError event

The Category parameter specifies the event category, which is source-specific information and can have any value.

The ID parameter specifies the event identifier, which is the message that goes with this event as an entry in the message file associated with the event source.
Avatar billede kroning Nybegynder
25. august 2005 - 10:44 #20
Det er ikke noget jeg har brugt så det har jeg ikke lige et forslag til.
Avatar billede kennethv Nybegynder
25. august 2005 - 11:33 #21
Øv. ;)
Avatar billede kennethv Nybegynder
31. august 2005 - 10:15 #22
Kroning: Kan man kalde en event på en anden komponent i en tråd, f.eks. ShellChangenotifier.OnChange eller en anden komponents event?
Avatar billede kroning Nybegynder
31. august 2005 - 11:46 #23
Hvis det er en event i hoved tråden så skal du bruge Synchronize, se hjælpen for hvordan man bruger den. Hvis det er en event som befinder sig i en anden tråd så skal der lidt mere til, det er ikke noget jeg har brugt jeg vil ikke begynde at forsøge at forklare det. Men kik evt. på http://www.pergolesi.demon.co.uk/prog/threads/ToC.html
Hvis du vil kalde en event i en tråd fra hoved tråden så kan du evt. bruge PostThreadMessage.
Avatar billede kennethv Nybegynder
01. september 2005 - 13:02 #24
Hvis man skriver:

procedure TWatchThread.Execute;
begin
  while not Terminated do
  begin
    Synchronize(ShellChangeNotifier1.OnChange);
    Sleep(500);
  end;
end;

procedure TService1.ShellChangeNotifier1Change;
begin
  Beep;
end;

så bliver synchronize udført hver gang. Korrekt? Nu er det sådan at ShellChangeNotifer har en properties "root" hvor jeg designtime har sat den til c:\test. Hvilket betyder at når der sker noget i c:\test skal den bipper 1 gang, men den gør det også hvis der sker noget i c:\ og det er ikke helt det der er meningen. Jeg havde forstillet mig at den selv holder styr på at noget er sket i "root".

Hvis jeg laver et alm prg hvor jeg i OnChange skriver:

procedure TService1.ShellChangeNotifier1Change;
begin
  Beep;
end;

vil den bippe 1 gang når noget er sket i "root".

Har du nogen ide til hvordan jeg kan gøre det i en service? Dit eksempel virker også, men kunne nu godt tænke mig at bruge ShellChangeNotifier. Vil gerne sætte flere point på spil.
Avatar billede kroning Nybegynder
01. september 2005 - 13:27 #25
Jeg har aldrig brugt ShellChangeNotifier og jeg har aldrig lavet en service så jeg er nok ikke den rette til at svare på det. Men prøv at lave et nyt spørgsmål så er der måske en anden der kan svare.
Avatar billede kennethv Nybegynder
03. oktober 2005 - 14:07 #26
Opgave lukket.
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester