Newsgroup: it.comp.lang.delphi
Titolo: ReadLn e array dinamico di puntatori a stringhe C-style

function getfile(filename: PChar): array of PChar;
[...]
<CTRL + F9>
[Error] Filesystem.pas(136): Identifier expected but 'ARRAY' found
["ma porca pupazza..."]
type
    	PPCharArray = array of PChar;
    	[...]
function getfile(filename: PChar): PPCharArray;
[...]
<CTRL + F9>
[nessun errore]
[e vai!!!]
function getfile(filename: PChar): PPCharArray;
    	var
            thearray: PPCharArray;
            thefile: text;
            i: Cardinal;
    begin
        Assign(thefile, filename);
        Reset(thefile);
        i:= 0;
        while not eof(thefile) do begin
            i:= i + 1;
            SetLength(thearray, i);
            ReadLn(thefile, thearray[i - 1]);
        end;
        getfile:= thearray;
    end;
<CTRL + F9>
[Error] Filesystem.pas(149): Illegal type in Read/Readln statement
[GIUDA! GIUDA! GIUDA PORCO!]
            [...]
            ReadLn(thefile, thearray[i - 1]^);
            [...]
[HAHAHAHA! ma quanto so' furba!!!]
<F7>
schermo:
<nulla>
[COOOSA? ma cazz... è vero...]
            [...]
            SetLength(thearray, i);
            thearray[i - 1]:= StrAlloc(0);
            ReadLn(thefile, thearray[i - 1]^);
            [...]
<F7>
schermo:
N
[ahemmm...]
<F7 - più forte>
schermo:
N
[uhm... *sgrat*sgrat*]
Riassunto: se passate un puntatore ad un buffer di caratteri, ReadLn 
vede e quindi scrive solo il primo carattere... (ho provato thearray[i - 
1]:= StrAlloc(BUF_SIZE); dove BUF_SIZE è una const uguale a 8192, ma il 
risultato è lo stesso)
Idee?
NOTA: ovviamente sto evitando volutamente di usare le stringhe native, 
per non portarmi dietro il gestore della memoria condivisa

 risultato è lo stesso)
Io lascerei perdere gli array dinamici, e anche ReadLn, che chiaramente non
e' adatto.
Userei piuttosto BlockRead o al massimo Read leggendo un byte alla volta..
magari non e' il massimo ma sicuramente funziona..
Userei dei normali buffer di memoria allocati con GetMem e li tratterei + o
meno dome le stringhe in C..
qualcosa tipo
var p:pchar;  // un puntatore;
begin
 GetMem(p, LunghezzaMassimaStringhe);
 BlockRead(file, pointer(p)^, lunghezza);
[..]
end;
Ciao !                        {MSX}

volta.. magari non e' il massimo ma sicuramente funziona..
ecco, non è il massimo. Pazienza.
esiste almeno una costante che mi dica quale carattere o sequenza di 
caratteri identifica la fine della linea?

caratteri identifica la fine della linea?
Non e' cio' che ti serve. BlockRead e' estremamente lento e ti
complicheresti la vita.
Vedi il mio esempio per capire come fare.
--
Andrea Laforgia (ICQ 87230455)
http://www.geocities.com/AndreaLaforgia
"ci sono tre tipi di persone nel mondo : quelli che
 sono bravi in matematica e quelli che non lo sono."

Idee?
Un esempio senza controlli d'errore :
program GetFile ;
{$APPTYPE CONSOLE}
uses
  SysUtils ;
type PPChar = array of PChar ;
function LoadTextFromFile( FileName : PChar ;
                           var ErrorFlag : Boolean ) : PPChar ;
var PCharArray : PPChar ;
    F : TextFile ;
    S : String ;
    I : Integer ;
begin
  ErrorFlag  := false ;
  PCharArray := nil ;
  AssignFile( F, FileName ) ;
  {$I-}
  Reset( F ) ;
  I := 0 ;
  while not Eof( F ) do
  begin
    ReadLn( F, S ) ;
    SetLength( PCharArray, I + 1 ) ;
    PCharArray[I] := StrAlloc( Length( S ) + 1 ) ;
    StrCopy( PCharArray[I], PChar( S ) ) ;
    Inc( I ) ;
  end ;
  CloseFile( F ) ;
  {$I+}
  Result := PCharArray ;
end ;
procedure WriteStrings( Strs : PPChar ) ;
var I : Integer ;
begin
  if ( Assigned( Strs ) ) then
  begin
    for I := Low( Strs ) to High( Strs ) do
      WriteLn( Strs[I] ) ;
  end ;
end ;
// Programma principale
var MyStrings : PPChar ;
    Error     : Boolean ;
begin
  MyStrings := LoadTextFromFile( 'D:\TC\BGIDEMO.C', Error ) ;
  if ( Error ) then
    WriteLn( 'Errore durante la lettura del file !' )
  else
    WriteStrings( MyStrings ) ;
  ReadLn ;  
end.


magari non e' il massimo ma sicuramente funziona..
No. ReadLn serve a leggere file di testo.
Leggere un byte alla volta, specie se l'input non e' bufferizzato
dalle routine Delphi (come in C), riduce moltissimo le prestazioni.


 dalle routine Delphi (come in C), riduce moltissimo le prestazioni.
si ma quella era la seconda scelta: la prima come dicevo era la BlockRead.
Ti assicuro che e' molto buona come scelta.

Ti assicuro che e' molto buona come scelta.
E' una scelta errata.
BlockRead per leggere un carattere alla volta da un file di testo non
e' la soluzione migliore. Questa funzione va usata su file binari per
leggere blocchi di byte (lo dice il nome stesso).
La lettura di un carattere alla volta, comparata con la lettura in
blocco (come quella di ReadLn) e' molto lenta.


Un esempio senza controlli d'errore :
tnx 1.0000000000E+03
non l'ho usato direttamente ma mi ha dato delle idee interessanti

 blocco (come quella di ReadLn) e' molto lenta.
non lo userei per leggere un byte alla volta.
Caricherei l'intero file in un buffer in un colpo solo e poi spezzerei le
linee di testo, mettendo i vari PChar all'inizio di ogni linea.
A pensarci bene non serve neanche ricopiarle dal buffer, le si puo' spezzare
gia' li sostituendo i caratteri #13#10 con due #0#0..
Sarebbe comunque una procedura estremamente veloce, lavorerebbe solo in
memoria facendo solo una chiamata I/O.

memoria facendo solo una chiamata I/O.
Non scherziamo.
Sorvolo sull'inutilita' di tale operazione, per sottolineare che
sarebbe comunque piu' lenta della lettura riga per riga (MOLTO piu'
lenta).


 lenta).
Per quanto riguarda l'inutilita' e' ovvia se si possono usare le stringhe.
Inizialmente pensavo non si potessero usare.
Quanto alla lentezza mi pare proprio che non sia' cosi' lenta, dato che e'
istantanea.

    del mio libro nero
dall'help di Delphi (ShareMem)
The shared-memory manager
If a DLL exports routines that pass long strings or dynamic arrays
as parameters or function results (whether directly or nested in records
or objects), then the DLL and its client applications (or DLLs) must
all use the ShareMem unit.
The same is true if one application or DLL allocates memory with New
or GetMem which is deallocated by a call to Dispose or FreeMem in another
module. ShareMem should always be the first unit listed in any program or
library uses clause where it occurs.
Perche' quest'avversione per lo shared memory manager?
Stai scrivendo una DLL?
Quindi non potresti (vorresti?) usare nemmeno gli arrai dinamici.
P.S. Le string SONO arrai dinamici.
Ciao!
Ammatwain.

    del mio libro nero
dall'help di Delphi (ShareMem)
The shared-memory manager
If a DLL exports routines that pass long strings or dynamic arrays
as parameters or function results (whether directly or nested in records
or objects), then the DLL and its client applications (or DLLs) must
all use the ShareMem unit.
The same is true if one application or DLL allocates memory with New
or GetMem which is deallocated by a call to Dispose or FreeMem in another
module. ShareMem should always be the first unit listed in any program or
library uses clause where it occurs.
Perche' quest'avversione per lo shared memory manager?
Stai scrivendo una DLL?
Quindi non potresti (vorresti?) usare nemmeno gli array dinamici.
Tra l'altro, le string sono array dinamici...
Ciao!
Ammatwain.

Quindi non potresti (vorresti?) usare nemmeno gli array dinamici.
Chi l'ha detto ?
Gli array dinamici si possono usare, se si usano internamente alle
funzioni, cosi' come le stringhe.


istantanea.
Non e' istantanea, e' inutile, e' lentissima, e' sbagliata e non ne
voglio parlare ulteriormente (considerando anche il fatto che il
problema e' stato gia' risolto).
<CODE>
// su PII a 450Mhz
procedure TForm1.Button1Click(Sender: TObject);
var Buffer : PChar ;
    F : File ;
    S : Integer ;
    R : Integer ;
    Time1, Time2 : DWORD ;
begin
  AssignFile( F, 'D:\TC\BGIDEMO.C' ) ; Reset( F, 1 ) ;
  S := FileSize( F ) ;
  GetMem( Buffer, S ) ;
  ShowMessage( IntToStr( S ) ) ;
  BlockRead( F, Buffer^, S, R ) ;
  Time1 := GetTickCount ;
  StringReplace( String( Buffer ), #13#10, #0#0, [rfReplaceAll] ) ;
  Time2 := GetTickCount ;
  ShowMessage( FloatToStr( ( Time2-Time1 ) / 1000 ) ) ;
  // output di 1,222 secondi per questo file
  // da 1 a 3 secondi per altri file della stessa dimensione
  CloseFile( F ) ;
end ;
</CODE>


 funzioni, cosi' come le stringhe.
mah! penso che l'abbia detto KJK :: Juliet
type
    PPCharArray = array of PChar;
function getfile(filename: PChar): PPCharArray;

function getfile(filename: PChar): PPCharArray;
Questo non e' incompatibile con altri linguaggi.
E' un semplice puntatore a puntatori.
Per capire il perche' dell'equivalenza con un "char**" del C, osserva
il codice che ho postato.


 il codice che ho postato.
mi sa che non mi sono spiegato...
non sto affermando nulla di preciso, ho solo riportato
testualmente l'help di delphi per cercare di chiarire la
storia della shared memory.
Ah! e visto che chi troviamo, lancio un appello:
--------------------------------------------
AIUTO!!! Qualcuno distrugga questo thread!!!
--------------------------------------------
;-)
Ciao Andrea
Ammatwain

 problema e' stato gia' risolto).
Vedi sopra:
1) ti ostini a dire che "e' sbagliata" quando invece funziona
2) e' veloce
Scusa ma non ho capito: sono io che ti sto dicendo il metodo o sei tu ? no
perche' la mia procedura che tra l'altro ti ho postato, fa quello che deve
fare in un tempo istantaneo. La procedura che c'e' qui sotto, e' un'altra
procedura che funziona in un altro modo, utilizza altre procedure
(StringReplace).
La mia ripeto, E' DIVERSA e ha tempi di esecuzione che ho detto.
Sono io che sto difendendo la MIA procedura. Se vuoi discuterne, devi
attaccare la MIA procedura, non quella che c'e' qui sotto. La mia e'
ovviamente piu' efficiente, utilizza i puntatori e non richiama altre
procedure.
Sinceramente non capisco come puoi ostinarti a criticare il mio metodo
facendo riferimento a qualcos'altro.
Prendi la mia procedura, la esegui, metti pure i Tick per calcolare il tempo
e dimmi quanto ti da.
Se qualcun'altro ha voglia, provi a eseguire la mia procedura e posti i
risultati corretti.


 risultati corretti.
Ci credo sulla parola che ci mette pochissimo!
Sono d'accordo con te.
poi per il metodo ognuno usa quello che vuole,
sinceramente io userei una stringa e tanto per farla breve se i files sono
piccoli farei una bella tstringlist, un bel loadfromfile dell'oggetto  e poi
l'assegnazione di tutte le stringhe in qualche maniera.
Naturalmente se la cosa è più importante e si trova in qualche cuore di
sistema ci penserei maggiormente. Mi sembra inoltre che il readln abbia
problemi a leggere righe più lunghe di tot caratteri, non ricordo bene se è
un problema attuale o era un problema nel passato. Mi sembrava di aver letto
tempo fa una "TI" nel sito Borland che parlava appunto di questo.
Nel metodo invece indicato (stringreplace..) può darsi che la lentezza sia
determinata dal fatto che ogni volta che fa una sostituzione si ricopia
tutta la stringa., ripetuta per n volte...
Matteo Tosato

 tutta la stringa., ripetuta per n volte...
Gia' credo proprio di si, anche perche' la StringReplace puo' sostituire una
stringa con una di diversa lunghezza..
io avevo anche pensato che potesse usare un metodo ricorsivo, che e'
sicuramente + lento di uno iterativo, anche se mi pareva strano.. e poi alla
stringreplace puoi dare una qualsiasi lunghezza per la stringa da cercare,
mentre la mia procedura funziona con 2 caratteri..
Ciao !!                            {MSX}