Newsgroup: it.comp.lang.delphi
Titolo: Import da file di testo.

Ciao a tutto il NG !
Ho bisogno di qualche buon consiglio...
Premetto che sono un principiante... ho iniziato da poco a usare D6.
Sto creando un'applicazione che importi in una DbGrid i dati presenti su un
file di testo. Ho adottato inizialmente il consiglio di qualcuno di
voi...(deo gratias!), e ho utilizzato il file sch per impostare lo schema di
import del mio file... e fin qui tutto bene... ma ora il problema è un po'
più incasinato.... siccome i campi del file di testo sono variabili... come
posso impostare il mio file sch in modo che i field della mia dbgrid siano
importati correttamente ? Ci sono altre possibilità secondo voi ? oppure
qual'è la soluzione più rapida e flessibile per risolvere la cosa ?
Vi ringrazio per le risposte
 A presto
Sparta

Per leggere un file di testo via BDE ti serve un sch.
Ora, la prima cosa che mi viene in mente è la sua creazione
dinamica.
Cioè, sapendo che il file ascii è fatto in un certo modo,
ti riscrivi a runtime il file sch e via.
Se poi esiste un qualcosa, tipo un componente, che riesca
a lavorare senza un file sch, si pone il semplice problema
se esso eredita da TDataset e puoi quindi utilizzarlo
come fonte dati per un controllo visuale dbaware.
Bye
AS
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 come fonte dati per un controllo visuale dbaware.
Ho trovato un esempio da D6 che mi ha installato un componente derivato dal
Tdataset che si chiama TTextData... ma il problema è che importa solamente
per linee e non colonne...
Non ho la più pallida idea sul come risolvere la questione...
Ti ringrazio cmq Alberto per il suggerimento... se ne avessi altri sono
sempre ben accetti.... :-)
Saluti
Sparta

> Non ho la piů pallida idea sul come risolvere la questione...
Domanda :
Ma i campi (le colonne) nel file di testo, sono separati da qualcosa di
riconoscibile ? (tipo un Tab, un ";" un pipe, o simili..)
Perchč se cosě fosse, io passerei senz'altro alla lettura del file di testo
aperto come TextFile, lettura delle righe con ReadLn, riconoscimento dei
delimitatori tra i campi con Pos(<delimitatore>) e fill dei record della tua
tabella.
Personalmente non ho mai utilizzato questi .sch, non li conosco proprio.
Se magari posti un'esempio di un paio dei record di questo file di testo,
posso anche vedere di mandarti qualche riga di codice.
Ciao.

 ha scritto nel messaggio
news:a7ft06$7uu$1...@newsreader.mailgate.org...


 Personalmente non ho mai utilizzato questi .sch, non li conosco proprio.
Se guardi nella guida del Bde trovi una spiegazione molto
chiara.
In pratica, un file sch č una specie di file INI che contiene
la definizione delle colonne.
Quando al bde dici di accedere ad un file txt ad esempio PIPPO.TXT
lui cerca un file sch di nome PIPPO.SCH che nella prima riga
ha, racchiusa tra parentesi quadre, il nome del file ascii.
Quindi, lui riesce a trattare il txt come una TTable.
Infatti, su questo tipo di file le query non sono ammesse.


 risultato poco elegante di avere un file di testo lunghissimo... :-)
Se hai una struttura fissa, ti crei un sch e poi tratti il file txt
come una ttable.
vedi nella guida del bde x i dettagli.


 per linee e non colonne...
Questo lo fai senza componenti aggiuntivi.
Prova ad aprire un file ascii senza un corrispondente sch
e vedrai nel field editor un solo campo: FIELD1 che include
la riga completa.


 posso anche vedere di mandarti qualche riga di codice.
Eccoti alcuni record del mio file di testo...
1                                |PROVA
|P|PRODOTTO FINITO|
2                                |ARTICOLO 1
|P|PRODOTTO FINITO|
Ti ringrazio per l'aiuto
Ciao !
Sparta

 Sparta
Ciao.
Oggi e domani sono "fuori sede" (da un cliente, in toscana).
Appeno posso ti mando l'esempio che ti dicevo.
Porta pazienza (se non arriva qualcun'altro prima).

 Si i campi sono separati da una linea verticale " | "
Carica il contenuto del tuo file di testo in una TStringList:
with TStringList.Create do
begin
  try
    LoadFromFile('tuofile.txt');
 
    // elabori le stringhe ...
  finally
    Free;
  end;
end;    
// ------- esempio di estrazione
function NextFieldValue(S: String;
                        Sep: Char;
                        Reset: Boolean): String;
const Idx: Integer = 1;
begin
  if Reset then Idx := 1;
  Result := '';
  while (S <> '') and (S[Idx] <> Sep) do
  begin
    Result := Result + S[Idx];
    Inc(Idx);
  end;
  if (S <> '') and (S[Idx] = Sep) then
    Inc(Idx);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
  S: String;
  T: String;
  I: Integer;
begin
  S := '1    |PROVA   |P  |   PRODOTTO FINITO|';
  for I := 1 to 4 do
    ShowMessage(NextFieldValue(S, '|', false));
end;


 Porta pazienza (se non arriva qualcun'altro prima).
Ti posto le mie mail: 
s.s...@osra.it
 , 
spa...@libero.it
Ti ringrazio nuovamente.
Sparta

Eccomi qua.
Questa è la 'mia' soluzione.
1) Metti un DBGrid, un DataSource ed un bottone su di una form.
2) Aggiungi il codice qui sotto all'OnClick del TButton.
Dato che la TTable viene create 'al volo', dovresti ricordarti di liberarla
all'uscita; dico 'dovresti' perchè in effetti, come da un thread passato, si
tratta solo di una preferenza; Infatti usando la Create(Self), di fatto
istruisci la Form (il 'self' in questione) a liberarsene all'uscita del
programma.
Vedi tu se è il caso.
Questo è il codice.
L'ho provato sui tuoi due record, e funziona correttamente.
A grandi linee fa questo :
1) Apre il file e scorre tutte le righe, cercando la riga che ha il numero
maggiore di campi (in caso questi possano essere diversi).
2) Chiudo e riapro (la Seek sui file di testo non è ammessa), e calcolo le
dimensioni massime per i campi trovati.
3) A questo punto ho sia il numero di campi che le dimensioni. Creo la
ttable run-time
4) Chiudo e riapro, leggo le righe e compilo i records della tabella.
5) Chiudo il file di testo, libero gli array dinamici e collego
Table->Datasource->DBgrid
Nota che io uso tabulazioni a 3 caratteri. Se tu le hai impostate
diversamente vedrai un bel casino.
Ciao.
//==========================================================================
====
procedure TForm1.Button5Click(Sender: TObject);
//==========================================================================
====
var
 TB  :TTable;
   i,
   n,
   Campi :integer;
   F  :TextFile;
   Riga :string;
   aLen :array of integer;
   aFld :array of string;
//--------------------------------------------------------------------------
-
   function ContaCampi(aRow :string) : integer;
//--------------------------------------------------------------------------
-
 var
    p :integer;
   begin
    Result := 0;
    p   := Pos('|',aRow);
  while p > 0 do begin
       inc(Result);
     aRow := Copy(aRow, p+1, length(aRow));
     p  := Pos('|',aRow);
      end;
   end;
//--------------------------------------------------------------------------
-
 procedure MisuraCampi(aRow : string);
//--------------------------------------------------------------------------
-
 var
    p,
      idx :integer;
      fld :string;
   begin
    idx := 0;
    p  := Pos('|',aRow);
  while p > 0 do begin
       fld := Trim(Copy(aRow, 1, p-1));
         if length(fld) > aLen[idx] then aLen[idx] := length(fld);
     aRow := Copy(aRow, p+1, length(aRow));
     p  := Pos('|',aRow);
         inc(idx);
      end;
   end;
//--------------------------------------------------------------------------
-
 procedure LeggiCampi(aRow : string);
//--------------------------------------------------------------------------
-
 var
    p,
      idx :integer;
      fld :string;
   begin
    idx := 0;
    p  := Pos('|',aRow);
  while p > 0 do begin
       aFld[idx] := Trim(Copy(aRow, 1, p-1));
     aRow := Copy(aRow, p+1, length(aRow));
     p  := Pos('|',aRow);
         inc(idx);
      end;
   end;
////////////////////////////////////////////////////////////////////////////
////
begin
 AssignFile(F,'File1.txt');
   Reset(F);
   // Conto i campi
   Campi := 0;
   ReadLn(F,Riga);
   while Riga<>'' do begin
    n := ContaCampi(Riga);
      if n>Campi then Campi := n;
      ReadLn(F,Riga);
   end;
   CloseFile(F);
   // Dimensiono l'array per le dimensioni massime dei singoli campi
   SetLength(aLen, Campi);
   // Riapro dall'inizio e calcolo le dimensioni massime per i singoli campi
   Reset(F);
   ReadLn(F,Riga);
   while Riga<>'' do begin
    MisuraCampi(Riga);
      ReadLn(F,Riga);
   end;
   CloseFile(F);
   // A questo punto so come dimensionare i campi della mia tabella,
   // e la creo a run-time.
   TB := TTable.Create(Self);
   with TB do begin
  TableType := ttParadox;
  Active  := False;
  DatabaseName:= '';
  TableName := 'Sparta';
   end;
   with TB.FieldDefs do begin
  Clear;
  for i:=0 to Campi-1 do
   with AddFieldDef do begin
    Name := Format('Fld%d',[i]);
    DataType := ftString;
    Required := False;
            Size  := aLen[i];
   end;
 end;
   TB.CreateTable;
   TB.Open;
   // Dimensiono l'array per la lettura dei campi
   SetLength(aFld, Campi);
   // Riapro il file e trasferisco i campi nella tabella
   Reset(F);
   ReadLn(F,Riga);
   while Riga<>'' do begin
    // Estraggo i campi dalla riga
    LeggiCampi(Riga);
      // Appendo un nuovo record alla tabella
      TB.Append;
      // Trasferisco i campi nel record
      for i:=0 to Campi-1 do
       TB.Fields[i].AsString := aFld[i];
      // Confermo il record
      TB.Post;
      ReadLn(F,Riga);
   end;
   CloseFile(F);
   aLen := nil;
   aFld := nil;
   Datasource1.DataSet := TB;
   DBGrid2.DataSource := Datasource1;
end;
////////////////////////////////////////////////////////////////////////////
////