Jak sprawdzić, czy plik jest otwarty?

0

Jak sprawdzić, czy plik jest otwarty?

0
AssignFile(plik, 'ścieżka_do_sprawdzanego_pliku');
try
    CloseFile(plik);
    ShowMessage('Plik był otwarty.');
except
    ShowMessage('Plik nie był otwarty.');
end;
0

Chciałbym odświeżyć nieco powyższy temat. Mam pytanie dotyczące obsługi plików poprze TFileStream. Jak sprawdzić czy dany plik,wybrany do wczytania oraz wykonania dalszych operacji np. edycja itp, jest już otwarty przez inną aplikację?
Robert

0

To, że też dotyczy dostępu do plików i sprawdzania czy inna aplikacja nie korzysta z pliku.

0

To czy plik jest w użyciu przez inny program, co utrudnia dostęp do niego poprzez zapis sprawdzisz tak jak pokazano w kodzie WinAPI, w wątku pod poniższym adresem: http://stackoverflow.com/questions/141302/checking-file-is-open-in-delphi o ile o to Ci chodzi.

Można też sprawdzić czy zmieniła się na przykład zawartość katalogu poprzez funkcję API ReadDirectoryChangesW. Opisano to pokrótce z przykładem pod następującym adresem http://stackoverflow.com/questions/863135/why-does-readdirectorychangesw-omit-events

0

Niestety to nie to.
Mój kod obecnie wygląda tak:

var
  fs_plik: TFileStream;
  s_nazwa: string;
  E: Exception;
begin
    fs_plik := nil;
  try
    try
    if not opnDialog.Execute then Exit;
      memPlikTekst.Lines.LoadFromFile(opnDialog.Filename);
      fs_plik:= TFileStream.Create(opnDialog.FileName, fmOpenRead or fmShareDenyNone);
      memPlikTekst.Lines.LoadFromStream(fs_plik);
      edtSciezkaPliku.Text:= opnDialog.FileName;
      s_NazwaPliku:= opnDialog.FileName;
     except
      on E: Exception do
        ShowMessage('Błąd = ' + E.Message);
    end;
  finally
    if Assigned(fs_plik) then FreeAndNil(fs_plik);

Chciałbym gdzieś w mój kod wpisać polecenia, które sprawdzą, że wybrany plik jest / lub nie jest używany przez inny program.

dodanie znacznika <code class="delphi"> - furious programming

0

To przecież kod podany przeze mnie w poprzednim postcie w pierwszym linku dokładnie to robi. Chodzi o to co wkleił tam użytkownik o nazwie JosephStyons. Jeżeli nie tego oczekujesz, to ja nic więcej raczej nie dodam.

0

Z jedną małą różnicą - przykład operuje zmienną typu HFile, a u mnie jest TFileStream

1

Wiesz, jestem wprawdzie po paru piwach, ale tolerancje na ulubione alko po grillowanym jedzonku mam ok. I ja w kodzie osobnika jakiego nick podałem, widzę czyste WinAPI i tak najlepiej go użyć.

function IsFileInUse(fName: string) : boolean;
var
  HFileRes: HFILE;
begin
  Result := False;
  if not FileExists(fName) then begin
    Exit;
  end;

  HFileRes := CreateFile(PChar(fName)
    ,GENERIC_READ or GENERIC_WRITE
    ,0
    ,nil
    ,OPEN_EXISTING
    ,FILE_ATTRIBUTE_NORMAL
    ,0);

  Result := (HFileRes = INVALID_HANDLE_VALUE);

  if not(Result) then begin
    CloseHandle(HFileRes);
  end;
end;

Sorry, ale pomimo usilnych starań, nie widzę tutaj próby otwierania niczego typu TextFile. Dla pewności można tylko i tak zwolnić uchwyt do pliku. Nawet jeśłi się ten plik uda otworzyć. A dalej już dłubać pod VCL, jeżeli taka Twoja wola.

2
{Najprostrzy sposób i za razem najlepszy}
function CzyPlikUzywany(Nazwa: string): boolean;
begin
 Result := not RenameFile(Nazwa,Nazwa);
end;

{lub modyfikacja powyższego}
function CzyPlikUzywany(Nazwa: String): Boolean;
var
 hPlik: hFile;
begin
 Result := not RenameFile(Nazwa, Nazwa);

 if not Result then
   begin
    hPlik  := CreateFile(pChar(Nazwa), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);
    Result := hPlik = INVALID_HANDLE_VALUE;
    if not Result then CloseHandle(hPlik);
   end;
end;

{Sposób 3}
function PlikUzywany1(Plik: string): Boolean;
var
 hPlik: TextFile;
begin
 try
  AssignFile(hPlik,Plik);
 except end;

 try
  {$I-}
  Reset(hPlik);
  {$I+}
 except end;

 if IOResult = 32 then Result := True
 else
 if IOResult = 0 then Result := False;

 try
  CloseFile(hPlik);
 except end;
end;

{Sposób 4}
function PlikUzywany2(Nazwa: string): boolean;
var
 Plik: file;
begin
 {$I-}
 Assign(Plik, Nazwa);
 FileMode := 0;
 Reset(Plik);
 Close(Plik);
 {$I+}
 Result := (IOResult = 0) and (Nazwa <> '');
end;
0

Dziękuje wszystkim za pomoc. W swoim programie wybrałem sprawdzanie Olesia. Oczywiście działa
Natomiast mam jedną zagwózdkę - po sprawdzeniu czy plik jest używany nie wychodzi z "try" - trzecie w procedurze, zamieniałem finally z tego bloku na except, ale jest jeszcze gorzej - możecie zerknąć co jest nie tak. Może kolejność ?

procedure TMainForm.btnOtworzClick(Sender: TObject);
var
  fs_plik: TFileStream;
  s_nazwa: string;
  E: Exception;
begin
    fs_plik := nil;
  try
    try
    if not opnDialog.Execute then Exit;
      s_nazwa:= opnDialog.FileName;
      try
      if CzyPlikOtwarty(s_nazwa) then
      begin
          ShowMessage('Plik jest uzywany przez inna aplikacje');
          btnWlasciwosci.Enabled:= False;
          exit;
        end;
      finally
//        memPlikTekst.Lines.LoadFromFile(opnDialog.Filename);
        fs_plik:= TFileStream.Create(opnDialog.FileName, fmOpenRead or fmShareDenyNone);
        memPlikTekst.Lines.LoadFromStream(fs_plik);
        edtSciezkaPliku.Text:= opnDialog.FileName;
        s_NazwaPliku:= opnDialog.FileName;
        btnWlasciwosci.Enabled:= True;
      end;
//    else
//          ShowMessage('Plik nie jest uzywany');

//    Alternatywa otwierania pliku
//    if not PromptForFileName
//        (s_nazwa, 'Pliki tekstowe (*.txt)|*.txt|Pliki *.dat|*.dat|Pliki *.csv|*.csv',
//         '', 'Otwórz plik danych', '', False) then Exit;
//      fs_plik:= TFileStream.Create(s_nazwa, fmOpenRead or fmShareDenyNone);
//      s_NazwaPliku := s_nazwa;
    except
      on E: Exception do
        ShowMessage('Błąd = ' + E.Message);
    end;
  finally
    if Assigned(fs_plik) then
      FreeAndNil(fs_plik);
    lblUtworzenie.Caption:= 'Data i czas utworzenia :';
    pnlRozmiarPlik.Caption:= 'Rozmiar pliku :';
    memStrumien.Text:= NullAsStringValue;
  end;
end;

dodanie znacznika <code class="delphi"> - furious programming

1

@roboskobo, nie ma takiej możliwości aby nie wychodził z try, już bardziej realnie brzmi: - "Włożyłem gwoźdź do kubka, odwracam kubek do góry nogami zaś gwoźdź nie wychodzi."

Kontynuując to co podał @Opi sposób 5:

function IsFileInUse(const FileName:String):Boolean;
var Fs:TFileStream;
begin
  Result:=false;
  try
    if not FileExists(FileName) then Exit;
    TFileStream.Create(FileName,fmOpenReadWrite).Free;
  except
    Result:=true;
  end;
end;
0

Ale masz na myśli wychodzenie z try tego ze sposobu 5 czy z try numer 3 w moim kodzie ?

0

Może nie wychodzić z pętli ale z try nie wychodzić nie może.

0

Rozumiem, więc jak zmodyfikować kod, aby po sprawdzeniu, czy plik jest używany pominąć wykonanie poniższej części kodu:

finally
        fs_plik:= TFileStream.Create(opnDialog.FileName, fmOpenRead or fmShareDenyNone);
        memPlikTekst.Lines.LoadFromStream(fs_plik);
        edtSciezkaPliku.Text:= opnDialog.FileName;
        s_NazwaPliku:= opnDialog.FileName;
        btnWlasciwosci.Enabled:= True;
 end;

dodanie znacznika <code class="delphi"> - furious programming

0
if not Warunek then
begin
  Akcja;
end;
0

Czy możecie zerknąć na ten kod ?

procedure TMainForm.btnOtworzClick(Sender: TObject);
var
  fs_plik: TFileStream;
  s_nazwa: string;
  E: Exception;
begin
    fs_plik := nil;
  try
    opnDialog.FileName:= NullAsStringValue;
    opnDialog.Execute;
    s_nazwa:= opnDialog.FileName;
    if opnDialog.FileName = '' then
      raise Exception.Create('Błąd = ' + E.Message);
  except
    on E: Exception do
    begin
      ShowMessage('Błąd = ' + E.Message);
      exit
    end;
  end;

  try
    try
      if not CzyPlikOtwarty(s_nazwa) then
      begin
//        ShowMessage('Plik nie jest uzywany');
        fs_plik:= TFileStream.Create(opnDialog.FileName, fmOpenRead or fmShareDenyNone);
        memPlikTekst.Lines.LoadFromStream(fs_plik);
        edtSciezkaPliku.Text:= opnDialog.FileName;
        s_NazwaPliku:= opnDialog.FileName;
        btnWlasciwosci.Enabled:= True;
        btnOdswiez.Enabled:= True;
        btnZapisz.Enabled:= True;
      end
      else
        raise EOtworzPlik.Create('Błąd = ' + E.Message);
    except
      on E: Exception do
        begin
          ShowMessage('Błąd = ' + E.Message);
          btnWlasciwosci.Enabled:= False;
          exit;
        end
    end
  finally
    if Assigned(fs_plik) then
      FreeAndNil(fs_plik);
    lblUtworzenie.Caption:= 'Data i czas utworzenia :';
    lblModyfikacja.Caption:= 'Data i czas modyfikacji :';
    pnlRozmiarPlik.Caption:= 'Rozmiar pliku :';
    memStrumien.Text:= NullAsStringValue;
  end;
end;
  1. Czy wyświetlenie numeru błędu np. w Memo może być realizowane tylko przy użyciu polecenia "case" czyli np. tak :
 case rgExceptions.ItemIndex of
    0: raise ELowError.Create('Niegroźny błąd!');
    1: raise EMediumError.Create('Niebezpieczny błąd!');
    2: raise EHighError.Create('Bardzo niebezpieczny błąd!');
  end;

to numer błędu jest 0, 1 lub 2.

  1. Czy w mojej procedurze można dopisać kod tak aby wyjątki przekazywać do wyższej procedury - odpowiedzialnej za wyświetlanie wyjątków ?
0
  1. Czy wyświetlenie numeru błędu np. w Memo może być realizowane tylko przy użyciu polecenia "case"

Możesz to zrobić na różne sposoby, np. wyłapywać wszystkie (to jest w Twoim zapisie), czy skorzystać z selektywnej obsługi wyjątków;

  1. Czy w mojej procedurze można dopisać kod tak aby wyjątki przekazywać do wyższej procedury - odpowiedzialnej za wyświetlanie wyjątków ?

Tak, wpisz samo słówko Raise wewnątrz bloku Except End, a wyjątek zostanie puszczony do procedury wyższego rzędu; Ale rzucanie i łapanie wyjątku w tym samym bloku jest zbędne - lepiej go stworzyć i nie obsługiwać, a zostanie przekazany do bloku wyższego rzędu automatycznie.

1

Ja tylko dodam, że to czy kliknieliśmy w OpenDialogu tak by wybrać plik do otwarcia nie powinno się sprawdzać:

opnDialog.Execute;
    s_nazwa:= opnDialog.FileName;

I tak dalej. Tylko najzwyczajniej w świecie skorzystać z rezultatu Execute. Czyli

if OpenDialog.Execute then // i dalej operacje na pliku pobranym z własności FileName
0

furious programming - Tak przeglądałem Selektywną obsługę wyjątków i trenuje po raz kolejny Listing 3.7 - ale bez rezultatu. Nie mogę uruchomić kodu tak aby coś się działo.
Możesz podpowiedzieć jak wykonać tak aby automatycznie przekazać wyjątek wyżej ?

**@olesio **- Tak miałem, ale wtedy nie mogłem wyświetlić wyjątku, gdy nie został wybrany żaden plik

0

Tak przeglądałem Selektywną obsługę wyjątków i trenuje po raz kolejny raz Listing 3.7 - ale bez rezultatu. Nie mogę uruchomić kodu tak aby coś się działo.

Pokaż więc kod, który nie działa prawidłowo, a coś się doradzi; Teraz nie wiem co masz i co ewentualnie źle zapisałeś;

Selektywna obsługa wyjątków może wyglądać np. tak:

type
  EFirstError  = class(Exception);
  ESecondError = class(Exception);

{..}

procedure Bald(const AValue: UInt8);
begin
  case AValue of
    1: raise EFirstError.Create();
    2: raise ESecondError.Create();
  end;
end;

procedure Foo(const AValue: UInt8);
begin
  try
    Bald(AValue);
  except
    on EFirstError  do Write('EFirstError was created');
    on ESecondError do Write('ESecondError was created');
  end;
end;

Przy czym procedura Bald rzuca wyjątek, ale go od razu nie obsługuje (jak jest u Ciebie), więc wyjątek podąża do procedury wyższego rzędu, czyli Foo; W niej, wywołanie procedury Bald wykonywane jest w bloku Except, więc klasa wyjątku zostaje sprawdzona oraz sam wyjątek zostaje obsłużony;

Podobnie musisz zrobić u siebie, ale nie musisz tworzyć własnych klas wyjątków, tak jak pokazałem w powyższym przykładzie.

0

@furious programming - czyli to co jest w procedurze Foo muszę wpleść w swoją procedurę?

0

Co co jest zapisane w procedurze Foo to wyłapywanie wyjątków, które może wywołać procedura Bald oraz ich selektywna obsługa; Czyli musisz zapisać coś na ten kształt, tyle że ze swoim kodem i swoimi klasami wyjątków.

0
roboskobo napisał(a):

**@olesio **- Tak miałem, ale wtedy nie mogłem wyświetlić wyjątku, gdy nie został wybrany żaden plik

Jakim cude?

  if opnDialog.FileName = '' then
      raise Exception.Create('Błąd = ' + E.Message);

Ten wyjątek? To podstaw to do tego samego bloku co po Execute. Ewnetualnie jeśli chcesz mieć to "niżej" w kodzie. To możesz podstawić wynik pod zmienną typu boolean, a później zrobić if not TaZmienna then i pokazać ten wyjątek. Choć według mnie, bez sensu rzucać wyjątkiem, kiedy nie wybrano pliku. Dajmy lepiej użytkownikowi programu możliwość wycofania się z tego, że chce otworzyć jakiś plik. Po co katować go aż tyloma wyjątkami. To imo bez sensu.

0

@furious programming wg Twoich wskazówek ale przekładając na mój kod za wywołanie wyjątków odpowiada "niższa procedura"

 procedure TMainForm.btnOtworzClick(Sender: TObject); 

, a do ich obsługi tworze sobie wyższą np. procedure TMainForm.ObslugaWyjatkow(Sender: TObject; E: Exception);

, która może wyglądać tak ? 
```delphi
begin
// procedura wyświetla komunikaty wyjątków
  Application.ShowException(E);
  try
    OtworzPlik(Sender);
  except
    on EOtworzPlik  do ShowMessage('Plik jest używany przez inną aplikację');
    on EZapiszPlik do ShowMessage('Nie wybrałeś pliku');
  end;
0

@roboskobo - w moim przykładzie także "niższa procedura" odpowiada za wywoływanie wyjątków (czyli procedura Bald), a "wyższa procedura" (czyli Foo) za ich przechwytywanie i obsługę;

To co podałeś to odzwierciedlenie mojego przykładu, ale w Twoim kodzie; Jeśli dobrze zrozumiałem Twój przykład, to właśnie tak powinieneś to zrobić; Ale nie pytaj się mnie, tylko po prostu sprawdź trasowanie wyjątków; Sprawdź, czy po zaistnieniu wyjątku wszystko zostanie obsłużone tak, jak sobie tego życzysz; Jeśli tak, to znaczy że dobrze to zrobiłeś.

1 użytkowników online, w tym zalogowanych: 0, gości: 1