Zapis danych do pliku *.csv

0

Poszukuję jakiejś podpowiedzi do zapisywania danych z różnych editów do jednego pliku *.csv.
Dajmy na to, że mam tabelę w excelu z trzema różnymi komórkami i chciałbym do nich zapisać trzy różne edity, w jaki sposób czegoś takiego dokonać?
Ma ktoś jakieś poradniki dotyczące delphi i plików csv ale takie gdzie przykładami nie będzie tabela w delphi a pojedyncze komponenty?

1

Mało w sieci bibliotek do obsługi plików CSV pod Delphi? Zobacz choćby tutaj:

http://www.codeproject.com/Tips/783493/Delphi-CSV-File-and-String-Reader-Classes

0

Znalazłem jakiś sposób na pliki *.xlsx

var
        Excel: Variant;
begin
        Excel := CreateOleObject('Excel.Application');
        Excel.WorkBooks.Add();
        Excel.Cells[1,1].Value := Edit1.Text;
        Excel.Cells[1,2].Value := Edit2.Text;
        Excel.Cells[1,3].Value := Edit3.Text;
        Excel.ActiveWorkbook.SaveAs('c:\plik.xlsx');
        Excel.Quit;

Jest to dla mnie wystarczające rozwiązanie, jednakże pytanie w jaki sposób odczytać prędzej zapisany plik *xlsx by dopisywać rekordy z Edit1,2,3.Text poniżej dopisanych prędzej?

0

[...] jednakże pytanie w jaki sposób odczytać prędzej zapisany plik *xlsx by dopisywać rekordy z Edit1,2,3.Text poniżej dopisanych prędzej?

A po polsku..?

0

Jednak jeśli @Zeelof nie ma narzuconego z góry formatu xlsx to ja bym nie polecał wymiany danych w tym formacie. O wiele lepsze i bardziej przenośny będzie csv.

0
furious programming napisał(a):

[...] jednakże pytanie w jaki sposób odczytać prędzej zapisany plik *xlsx by dopisywać rekordy z Edit1,2,3.Text poniżej dopisanych prędzej?

A po polsku..?

heh, faktycznie nieco chaotycznie wyszło a jednak ma sens ;P
Po prostu chcę cały czas działać na jednym pliku gdzie będę dopisywać coraz to niżej jakieś rekordy z tych samych editów.
A swoją drogą w przypadku Twojej wypowiedzi o plikach csv, również ciśnie się to samo pytanie - "A po polsku..?" bo będąc na polskim forum szukam pomocy właśnie w tym języku ;)

Mr.YaHooo napisał(a):

Jednak jeśli @Zeelof nie ma narzuconego z góry formatu xlsx to ja bym nie polecał wymiany danych w tym formacie. O wiele lepsze i bardziej przenośny będzie csv.

A miałbyś jakiś poradnik dotyczący plików csv gdzie w delphi nie musiałbym korzystać z komponentów tabeli tylko tak jak opisałem wyżej?

0

A miałbyś jakiś poradnik dotyczący plików csv gdzie w delphi nie musiałbym korzystać z komponentów tabeli tylko tak jak opisałem wyżej?

@Zeelof - możesz ręcznie tworzyć pliki CSV, bez konieczności używania dodatkowych bibliotek i obiektów, ale nie będziesz miał pewności, że tak przygotowane pliki będą w 100% zgodne ze standardem; Biblioteki istnieją po to, aby zadbać o pełną i prawidłową implementację, a także dać możliwość wygodnej obsługi takich plików i danych w nich zawartych.

0

Problem w tym, że mam już dobrze działający program i chciałbym by wprowadzane do niego dane byly zapisywane w fomie arkusza kalulacyjnego. Sam program nie ma tabeli a pelno editow ktore chcialbym poszuflatkowac do odpowiednich komorek excela.

0

Ty myślisz, że do używania plików CSV trzeba mieć formularz ze StringGridem?

0

Nie, jednak jak bym nie szukał widzę tylko przykłady dotyczace formularza

0

Może to przez to że mało spałem ale ja dalej nie rozumiem co chcesz zrobić. Masz n editów wpisujesz dane i ma Ci się to składować np w kolumnie BX w excelu tak?

0

Dokładnie tak, jednakże każde zapisanie danych z tych editów ma dopisywać do tabeli w BX+1 i za każdym razem ma działać na jednym pliku, czyli wyłączę aplikację i po ponownym jej uruchomieniu wczytuje ten sam plik arkusza i dopisuje poniżej istniejących już rekordów nowe.

0

Ok rozumiem, pytanie zatem czy to musi być CSV/Excel? Pytam gdyż to co potrzebujesz idealnie wpasowałoby się w najprostszą z możliwych struktur SQLite (tabela + insert). Co do CSV możesz korzystać z gotowych bibliotek (choć z nimi różnie bywa) lub parsować to samemu - rzeźba jak się patrzy. Co do samego Excela to też nie jest problem bo przykład który podałeś z tworzeniem OLEObject też się da jednakże ma to pewien minus bo na kompie na którym to odpalasz MUSI być zainstalowany Excel. SQLite jest znacznie wygodniejszy do takiego zastosowania.

PS. Jeżeli faktycznie musisz mieć CSV to ja ostatnio to załatwiłem jedną funkcją: ExtractStrings a co za tym idzie najzwyczajniejszym w świecie TStringList

0

Ostatecznie musi to być niestety excel a najlepiej csv. Faktycznie dane można by początkowo gromadzić do bazy SQL jednak i tak potrzebowałbym możliwość eksportowania danych z jakiegoś przedziału do pliku excel.

0

Zapoznaj się z obsługą klasy, która umożliwia ładowanie, zapisywanie i edycję takich plików; Jak dowiesz się tego, w jaki sposób dodawać nowe wiersze - przestaniesz się martwić tym skąd dane będą pochodzić;

I raczej nie twórz takich plików ręcznie, bo mogą one odbiegać od standardu CSV, którego trzyma się Excel; Użyj dedykowanej biblioteki - raz, że zapewnisz kompatybilność ze standardem, dwa, że będziesz miał wygodne w użyciu klasy; Pisałem Ci o tym wczoraj, a Ty nadal zastanawiasz się, zamiast pobrać bibliotekę i coś popróbować.

0

Może inaczej.
Odczytywanie do komponentu arkusza wygląda mniej więcej tak:

var i:integer;
    f:textfile;
    s:string;
begin
  AssignFile(f,'Tabela.csv');
  Reset(f);
  with StringGrid1 do
  for i:=0 to RowCount-1 do
  begin
    Rows[i].Delimiter:=';';
    Readln(f,s);
    Rows[i].DelimitedText:=s;
  end;
  Closefile(f);
  ShowMessage('Plik odczytany');

Zapis:

var i:integer;
    f:textfile;
begin
  AssignFile(f,'Tabela.csv');
  Rewrite(f);
  with StringGrid1 do
  for i:=0 to RowCount-1 do
  begin
    Rows[i].Delimiter:=';';
    Writeln(f,Rows[i].DelimitedText);
  end;
  Closefile(f);
  ShowMessage('Plik zapisany');

Całość oczywiście działa, pytanie jednak jak mogę wyciągnąć dane z wybranych komórek (np. A3 i D7) pliku csv bezpośrednio do np. Label1.Caption i Label2.Caption?
Właśnie dopiero w tym miejscu pojawia się u mnie problem.

1

Słuchaj @Zeelof @furious programming podał Ci na początku gotową klasę gdzie masz zapis i odczyt ustawiony. Co do samego pobierania danych z A3 to w CSV czegoś takiego nie ma bo to zasadniczo ciąg znaków oddzielony separatorem. Kolumna A zatem to Twoja pierwsza wartość od lewej (przed separatorem) numer natomiast to numer wiersza z pliku. Nie ma takiej funkcji jak:

function CSV.GetValueFromColumnLine('A',3): string

. Możesz sobie takie coś oprogramować dłubiąc ręcznie lub sprytnie działając pętlami na klasach, które podał Ci @furious programming

0

Udało mi się to jakoś ogarnąć, jednakże jeszcze inaczej.
Okazało się, że wszystko generowane jest w tablicy i wystarczyło:

Label1.Caption := Rows[0][0];

Dzięki wielkie wszystkim za pomoc ;)

0

Okazało się, że wszystko generowane jest w tablicy i wystarczyło:

Label1.Caption := Rows[0][0];

Aha, teraz nagle się okazało... A to Rows to niby co to jest? Gdzie to jest zadeklarowane i jakiego to coś jest typu? I dlaczego wcześniej tego nie pokazałeś?

0

A jeśli to musi być CSV to może skorzystać jednak zamiast klasy to mechanizmu ADO? Z plikami CSV pracuje dość sprawnie i można do danych dobierać się za pomocą zapytań SQL, ewentualnie jako tabela. A to co kolega opisuje dla mnie bardzo pasuje aby traktować to kontrolkami db-aware.

0

Mi takie rozwiązanie wystarczy. Teraz potrzebuje tylko zrozumieć jak dodać coś do najbliższego pustego wiersza by nie nadpisywać zapisanych wcześniej komórek.

  if not FileExists(StringGrid1.Cells[1, 2]) then
    StringGrid1.Cells := IntToStr(StrToInt(StringGrid1.Cells[1, 2]) + 1);

;/

0

Przecież o ile kojarzę Cells nie jest własnością read only, więc w czym problem? ;/ Naprawdę to jakiś problem wpisać w Google delphi stringgrid i zobaczyć stronę z pierwszego wyniku? Wcześniej nie chciałeś "ekspresu do kawy". A teraz wyraźnie widać, że chyba lubisz sobie sam robić problem gdzie go nie ma i niepotrzebnie utrudniać. Ale jak uważasz ;/

0

Ale powiedz co mi po ekspresie do kawy jak nie rozumiem instrukcji obsługi?
Znalazłem zaś przykład tego typu:

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    StringGrid1: TStringGrid;
    Label1: TLabel;
    procedure Button4Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var i:integer;
    f:textfile;
begin
  AssignFile(f,'Tabela.csv');
  Rewrite(f);
  with StringGrid1 do
  for i:=0 to RowCount-1 do
  begin
    Rows[i].Delimiter:=';';
    Writeln(f,Rows[i].DelimitedText);
  end;
  Closefile(f);
  ShowMessage('Plik zapisany');
end;

procedure TForm1.Button2Click(Sender: TObject);
var i:integer;
    f:textfile;
    s:string;
begin
  AssignFile(f,'Tabela.csv');
  Reset(f);
  with StringGrid1 do
  for i:=0 to RowCount-1 do
  begin
    Rows[i].Delimiter:=';';
    Readln(f,s);
    Rows[i].DelimitedText:=s;
  end;
  Closefile(f);
  ShowMessage('Plik odczytany');
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  I, J, K : Integer;
begin
  K := 0;
  with StringGrid1 do
    for I := 0 to ColCount - 1 do
      for J:= 0 to RowCount - 1 do
        begin
          K := K + 1;
          Cells[I,J] := FloatToStr(K*0.1);
        end;
end;

procedure TForm1.Button4Click(Sender: TObject);
var i: integer;
begin
  with StringGrid1 do
    for I := 0 to ColCount - 1 do Rows[i].Clear;
end;

end.

I ten kod jest dla mnie w miarę do zrozumienia.

Ale wracając do pytania.
Na googlu w pierwszym linku jaki podałeś pojawia się kolejny dość długi i toporny kod...
Potrzebuje raczej czegoś co nie zmusi mnie do głupiego i ciągłego pisania:

if not FileExists(StringGrid1.Cells[1, 2]) then
   StringGrid1.Cells[1, 3] := 'zawartość';
0

Widziałem ten kod jednakże niezbyt rozumiem z czym się to je...

0

Ech @Zeelof testujesz naszą cierpliwość.

  1. Masz ileś editów (pierwsze uruchomienie aplikacji) -> robisz zapisz -> powstaje plik. Jak rozumiem tą kwestię masz już ogarniętą.
  2. Ponowne otwarcie aplikacji powoduje wczytanie pliku zapisanego w kroku 1 - To też masz pewnie zrobione
  3. Wpisujesz coś do edita i nie chcesz nadpisać jakieś wartości tylko dopisać nową - rozumiem, że tu masz problem. Jeśli tak to dla przykładu jeżeli przy odczycie z pliku (2) wsadziłeś cały plik do stringgrida to używając pętli for po kolumnach (ColCount) i wartości RowCount wiesz co jest ostatnie więc RowCount+1 automatycznie oznaczają nowy ostatni dodany rekord.

PS.
Masz tu jeszcze jednego linka odnośnie stringgridów. Choć formatowania kodu tam nie ma to jest wszystko co moim zdaniem potrzebujesz zrobić z gridem: http://www.awalum.com/x_delphi/tstringgrid.htm
i jeszcze jeden tyle, że po angielsku
http://www.asiplease.net/computing/delphi/string_grid_component.htm

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