Kłopot z wczytywaniem pliku.

0

Witam,

muszę napisać program, który wykonuje proste operacje na pliku tekstowym, chciałem wykorzystać do tego kod (pisany na jakiś lekcjach), ale ciągle dostaje komunikat że plik nie istnieje z warunku, który ma to sprawdzić. Nie wiem czy plik musi być w jakiejś innej lokalizacji (w tej chwili jest w tym samym folderze co pliki lazrusa). Poniżej kod :

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);

  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;
  fp: TextFile;
  nazwa, str: string;
  I: Integer;

implementation

{$R *.lfm}

{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Clear;
  nazwa:='t.txt';
  Assignfile(fp, nazwa);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  str:string;
begin
  if not fileexists(nazwa) then
     ShowMessage('Plik nie istnieje!')
  else begin
   Memo1.Clear;
   Reset(fp);
   while not eof(fp) do
   begin
     Readln(fp, str);
     Memo1.Lines.Add(str);
    end;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;
begin
  Rewrite(fp);
  for I := 0 to Memo1.Lines.Count-1 do
  begin
      writeln(fp, Memo1.Lines[I]);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
   CloseFile(fp);
end;

end.

Piszę, bo skończyły mi sie pomysły i będę wdzięczny za każda pomoc.

3

Według mnie musisz albo umieścić go w katalogu z projektem lub dla pewności dodać ExtractFilePath(ApplicationExeName) + 'nazwa_pliku.txt'; Poza tym po co pod LCL stosujesz konstrukcje rodem z konsolowego Pascala? Przecież Memo ma gotowe mechanizmy do tego. Jak Lines.LoadFomFile i Lines.SaveFromFile.

1

@s-f - poprzednik podał Ci metody, które możesz śmiało wykorzystać;

Jeśli o samo ładowanie pliku chodzi, to przede wszystkim odwołuj się do niego za pomocą pełnej ścieżki, czyli użyj funkcji ExtractFilePath z pobranej za pomocą funkcji ParamStrUTF8 nazwy pliku wykonywalnego; Dzięki temu zabezpieczysz się przed błędami, jeśli nazwa pliku lub ścieżki zawiera znaki spoza strony kodowej ASCII/ANSI; Czyli użyj takiej konstrukcji:

var
  strFileName: UTF8String; { lub AnsiString, albo String }
begin
  strFileName := ExtractFilePath(ParamStrUTF8(0));

Po drugie, do sprawdzenia czy plik lub katalog istnieje, należy użyć funkcji FileExistsUTF8 lub DirectoryExistsUTF8; To samo - jeśli nazwa lub ścieżka zawiera multibajtowe znaki (np. polskie znaki diakrytyczne lub inne znaki z obcych alfabetów), to te funkcje pozwolą na poprawne ich sprawdzenie; Czasy strony kodowej ANSI już dawno minęły, więc i Lazarus domyślnie obsługuje kodowanie UTF-8;

Po trzecie - jak już koniecznie chcesz się bawić i starym sposobem ładować/zapisywać pliki to przenieś te wszystkie zmienne globalne (oprócz zmiennej klasy formularza) do wnętrza klasy okna - zmienne globalne to zło i trzeba ich unikać;

No i jeszcze jedna sprawa; Jeżeli piszesz warunek, który ma także obsługiwać coś po Else, to najpierw zapisuj to co będzie wykonane po spełnieniu warunku, a dopiero po Else to co będzie wykonane, gdy warunek nie zostanie spełniony; U Ciebie widzę w warunku operator Not, a to nie jest dobry zwyczaj;


Podsumowując - sugeruję taką konstrukcję:

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FFileName: UTF8String;
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FFileName := ExtractFilePath(ParamStrUTF8(0)) + 't.txt';
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if FileExistsUTF8(FFileName) then
    Memo1.LoadFromFile(FFileName)
  else
    ShowMessage('Plik nie istnieje!');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.SaveToFile(FFileName);
end;
0

Panowie, najpierw chciałbym przeprosić, że odpisuje dopiero teraz, ale nie miałem czasu, żeby tym się zająć wcześniej.

Obie Wasze odpowiedzi były bardzo pomocne. Przyznam się szczerze, że skorzystanie z LCL jest lepsze :)

Mam tylko jeden problem, jak wpiszę ścieżkę z ręki to wszystko ładnie działa, ale jak próbuje skorzystać z ExtractFilePath to nie może odnaleźć pliku.

Jak skasuje warunek, który sprawdza czy plik istnieje i uruchomię program to dostaje taki komunikat:

Unable to open ""

Przy czym jak wyświetliłem ścieżkę to powinno być wszystko dobrze. Macie może jakieś sugestie?

0

Mam tylko jeden problem, jak wpiszę ścieżkę z ręki to wszystko ładnie działa, ale jak próbuje skorzystać z ExtractFilePath to nie może odnaleźć pliku.

Pokaż więc przykład wpisanej na sztywno ścieżki (która działa) oraz instrukcji z użyciem ExtractFilePath, która nie może odnaleźć pliku; Bo coś ciężko mi w to uwierzyć, że choć plik istnieje, to program nie może go załadować.

0

Wpisałem takie coś:

ShowMessage( ExtractFilePath(ParamStrUTF8(0)) + 't.txt');  

żeby sprawdzić jaką ścieżkę zwraca i dostaje coś takiego: C:Users\...\t.txt
Ścieżka dobra, ale całość nie działa (korzystam z kodu powyżej)

Natomiast jak wpiszę to:

Memo1.Lines.LoadFromFile('C:\Users\...\t.txt')

to wszystko działa.

0

żeby sprawdzić jaką ścieżkę zwraca i dostaje coś takiego: C:Users\...\t.txt

Jeśli dobrze przekopiowałeś (lub przepisałeś) tę ścieżkę z programu, to wychodzi na to, że funkcja ExtractFilePath zwraca błędną ścieżkę - brakuje znaku \ po C:; No i nie wiem dlaczego wewnątrz jej znajduje się sekwencja ... - tak się nie zastępuje skróconych nazw katalogów.

0

... - użyłem żeby skrócić ścieżkę, ale tylko w poście, normalnie jest cała :P

Po przeczytaniu Twojego posta sprawdziłem jeszcze jedną rzecz. Jak wpisuje tak:

Memo1.Lines.LoadFromFile(ExtractFilePath(ParamStrUTF8(0)) + 't.txt')

To działa, ale jak próbuję skorzystać z tego przypisania:

FFileName := ExtractFilePath(ParamStrUTF8(0)) + 't.txt';

to wyskakuje mi błąd, o którym pisałem wcześniej. Niby może zostać tak jak zrobiłem, ale zastanawia mnie dlaczego ten sposób z przypisaniem ścieżki nie działa?

dodanie znaczników <code class="delphi"> - @furious programming

0

Pokaż więcej kodu szczególnie kiedy jest wywoływana linia

FFileName := ExtractFilePath(ParamStrUTF8(0)) + 't.txt';

oraz jak korzystasz później z FFileName
Na moje próbujesz skorzystać ze zmiennej FFileName zanim pobierzesz ścieżkę - no innej opcji nie ma.

0

To jest całość:

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  LCLType, ValEdit;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);


  private
    { private declarations }
    FFileName: UTF8String;

  public
    { public declarations }
  end;

var
  Form1: TForm1;


implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  FFileName := ExtractFilePath(ParamStrUTF8(0)) + 't.txt';
end;


procedure TForm1.Button2Click(Sender: TObject);
begin
   if FileExistsUTF8(FFileName) then
      Memo1.Lines.LoadFromFile(FFileName)
   else
       ShowMessage('Plik nie istnieje!');
end;


end.

W sumie tak jak teraz na to patrze to nie wiem czy jak FFileName jest w innej procedurze to ma to prawo działać?

0

FFileName jest częścią klasy (dokładniej polem prywatnym) i jest widziane w całej klasie TForm1.
U mnie ten przykład działa - testuje na XP.
Po co pobierasz w ogóle całą ścieżkę jak można użyć ścieżki względnej tj. FFileName := 't.txt';

0

Dobra pogubiłem się jak mam taki kod:

procedure TForm1.FormCreate(Sender: TObject);
begin
  FN := 't.txt';
end;


procedure TForm1.Button2Click(Sender: TObject);
begin

   if FileExists(FN) then
      Memo1.Lines.LoadFromFile(FN)
   else
       ShowMessage('Plik nie istnieje!');
end;

To kiedy warunek sprawdza czy plik istnieje, dostaje komunikat po else (czyli 'Plik nie istnieje!')

Natomiast jak zrobiłem tak:

procedure TForm1.Button2Click(Sender: TObject);
begin
     FN := 't.txt';
   if FileExists(FN) then
      Memo1.Lines.LoadFromFile(FN)
   else
       ShowMessage('Plik nie istnieje!');
end;

to zadziałało, więc już kompletnie nic nie rozumiem. Może mi brakować jakiejś biblioteki, coś nie tak z kompilatorem? Skoro u Ciebie działa a u mnie nie?

dodanie znaczników <code class="delphi"> - @furious programming

2

Dodałeś do sekcji interface wpis samodzielnie? Prawdopodobnie tak. Pisałem ci w innym temacie, żebyś tak nie robił i generował zdarzenia przez zakładkę Zdarzenia.
Zatem skasuj to.
Kliknij na Formularz przejdź w inspektorze obiektów do zakładki "Zdarzenia" odszukaj tam "OnCreate", 2 klik i masz wygenerowane zdarzenie "FormCreate" i co ważne podpięte pod formularz. (To samo możesz osiągnąć przez 2 klik na formularzu).

0

Myślałem że tyczy sie to samych obiektów, które wstawiam. Nauczka na przyszłość, dzięki.

0

Kodowanie znaków:

if FileExistsUTF8(FFileName) then
      Memo1.Lines.LoadFromFile(UTF8ToAnsi(FFileName))
   else
       ShowMessage('Plik nie istnieje!');

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