Newsgroup: it.comp.lang.delphi
Titolo: TFileSTREAM

Ciao a tutti.
Stò cercando di utilizzare gli offetti TFileStream.
Io devo leggere un filee ricercare al suo interno alcune particolari
sequenze di byte.
Se realizzo un ciclo del tipo:
AssignFile(f,'xxx.xxx');
Reset(f);
While non eof(f) Do
Begin
    Read(f,ch);
    ifi ch = XX then......
End;
Funziona tutto ma ci mette un sacco di tempo in quanto per ogni byte il
programma esegue un accesso al disco.
Ho tentato di utilizzare il BlockRead ma può capitare che la sequenza di di
byte di mio interesse capiti a "cavallo" di bue Buffer letti in successione
e quindi non riesco a riconoscerli correttamente a meno che non mi inventi
delle cose estremamente strane.
Ho pensato di utilizzare gli oggetti TFileStream.
Io credo che posso caricare il contenuto del file in un oggetto di questo
tipo e poi scorrerlo e cercare le sequenze di mio interesse.
Io ho agito in questa maniera:
var
  f_s:TFileStream;
begin
    f_s.Create(OpenDialog1.fileName,fmOpenRead);
End;
Sin qui tutto OK, Ma se io ora voglio leggere i byte contenuti all'interno
di f_s?
Io ho provato ad usare
    f_s.Read(Buffer,Count); Il quale dovrebbe leggere un Buffer di byte dal
f_s costituito da Count elementi.
Ma Buffer che tipo di struttura è?
Come la devo definire?
E' forse un record di Byte?
Grazie per la gentile attenzione,
Giorgio.
**************************************
Giorgio Marinangeli
ICQ 12941403
http:\\
web.tiscalinet.it/gmsoft
Attenzione: in febbraio 2001 l'indirizzo
mgio...@cronosnet.com
VERRA' DISABILITATO.
Il nuovo indirizzo già disponibile è:
E-Mail: 
ma.gi...@tiscalinet.it
.
*************************************

 E' forse un record di Byte?
Buffer è un buffer nel vero senso della parola.
Cioè è un tipo di dato compatibile con i dati che vuoi leggere dal file.
Cioè quando tu leggi un file, dovresti conoscerne il formato, cioè come sono
"organizzati" e che significato hanno i vari byte che lo compongono.
Se i primi quattro byte del file sono un numero a 32 bit con segno, si
tratta di un tipo Integer 32 bit ( signed ) e quindi Buffer è una variabile
di tipo Integer. Poi il metodo Read lo usi in questo modo:
f_s.Read(Buffer_Tipo_Integer, SizeOf(Buffer_Tipo_Integer));
dove la funzione SizeOf ti restituisce il numero dei byte che occupa il
Buffer che dovrà essere riempito con i byte letti, quindi nel caso di un
integer restituirà 4 che poi sono 32 bit.
Quando hai fatto la lettura, se ti vai a riportare in un campo di tipo testo
( che visualizzi sul video ) il valore della variabile Buffer_Tipo_Integer,
ti comparirà il valore numerico letto. ( tale valore risulta dalla
conversione del quattro byte secondo la rappresenzazione binaria dei tipi
Interi ).
Quindi se tu leggi un gruppo di byte e lo interpreti in un'altra maniera,
avrà un significato completamente diverso e sicuramente errato.
A parte ciò, se vuoi leggere tutto il file e piazzarlo in memoria
lavorandoci sopra, puoi usare la classe TMemoryStream, oppure altri metodi
della TFileStream leggendo quindi il file a blocchi piazzando i byte letti
in buffer ( magari array di byte ) da te definiti. La lettura a blocchi sarà
perfetta e velocissima. Ok ?
Se non hai capito qualcosa fai un fischio e chiarirò i tuoi dubbi.
Ti saluto....ciao !!
Antonio Tarolla

 f_s:=TFileStream.Create(OpenDialog1-fileName, fmOpenRead);
hem... diciamo che il primo non va e il secondo invece č la sintassi
corretta ?  ;-)
ciao, DavideDG


In realtà una cosa di questo tipo è lecita
with TFileStream.create(OpenDialog1-fileName, fmOpenRead) do begin
  seek(0,0);
  read(buffer,size);
  free;
end;
quindi anche il primo va ed è sintatticamente corretto.
Ciao
Ruggero

 End;
Questo codice produce un errore di violazione di accesso... perchè accedi ad
un componente che non è stato ancora inzializzato (f_s).
Ciao, Davide DG

"Davide DG":
| Nell'esempio di Giorgio ;
| > var
| >   f_s:TFileStream;
| >
| > begin
| >
| >     f_s.Create(OpenDialog1.fileName,fmOpenRead);
| >
| > End;
|
| Questo codice produce un errore di violazione di accesso... perchè accedi
ad
| un componente che non è stato ancora inzializzato (f_s).
esattamente, e' cio' che pensavo anch'io,
in effetti teoricamente parlando dovrebbe dare
un access violantion, e invece no!
Provalo, e soprattutto trovami una
risposta a questo dilemma che non ha alcun senso! :)
Ciao!
Alan Solo

 risposta a questo dilemma che non ha alcun senso! :)
Ehm... *proprio* perchè l'ho provato (D5 Ent.) e mi dà un access violation
(come è prevedibile)
posso affermare quello che dico...
Il codice che ho provato io è :
Implementation
Var F_S : TFileStream;
       X : Array [0..1024] of char;
Procedure TForm1.Button1Click (Sender : TObject);
Begin
    f_s.Create('C:\MSDOS.SYS',fmOpenRead);  // -> EAccessViolation... read
of Address FFFFf...
// sintassi giusta (e funzionante) : f_s := TFileStream.Create
('C:\MSDOS.SYS',fmOpenRead);
    f_s.read(x,sizeof(x));
    f_s.free;
   caption := X;
End;
Del resto, la sintassi IstanzaOggetto := TOggetto.Create, anche se
"anomala", è più "corretta" se pensi che
una cosa come IstanzaOggetto.Create  significherebbe chiamare il costruttore
di un oggetto non ancora costruito.
Una curiosità ... in C mi sembra che le cose siano diverse (+ pulite)...
com'è la sintassi di creazione ?
Ciao!! Davide DG

 risposta a questo dilemma che non ha alcun senso! :)
riguardo l'istruzione with, è logico che funziona ( il suo scopo, oltre a
semplificare, è quello ) ed infatti sono pienamente d'accordo su quanto
detto da Davide.
Poi riguardo f_s.Create usato direttamente, non l'ho mai provato e per
questo non mi sono sbilanciato più di tanto quando ho risposto alla domanda.
Insomma mi sono limitato a dire che la nostra inizializzazione fosse "più
carina" della sua visto che lui non lamentava difetti.
Magari non da subito errore perchè il metodo "Create" non è una normale
procedura, ma un costruttore ed ora non so che privilegi abbia, ma
sicuramente qualcuno di più rispetto ad un normale metodo.
Comunque la sintassi da lui usata:
f_s.Create(ecc....)
manca dell'assegnazione vera e propria. In questo caso ho notato che la
dimensione dell'istanza è nettamente maggiore ( o fasulla ) rispetto alla
normale dimensione ottenuta con una corretta inizializzazione !!!
Poi non ho fatto altre prove, anche perchè io ritengo esatta e più elegante
( e pure più logica ) la nostra ( e classica ) inizializzazione.
Con questo vi saluto e magari seguirò il thread per curiosare altre
( chissà ) ipotesi.
Ciaooo !!!
Antonio Tarolla

"Davide DG":
| Ehm... *proprio* perchè l'ho provato (D5 Ent.) e mi dà un access violation
| (come è prevedibile)
| posso affermare quello che dico...
ti assicuro che con il 4 non da' alcun errore!
boh,  forse e' un probema del compilatore o
ho un qualche settaggio strano (ma non credo)...
| Del resto, la sintassi IstanzaOggetto := TOggetto.Create, anche se
| "anomala", è più "corretta" se pensi che
| una cosa come IstanzaOggetto.Create  significherebbe chiamare il
costruttore
| di un oggetto non ancora costruito.
si', e' quello che ho detto, appunto per questo mi sono stupito
quando il compilatore non mi 'ha detto' niente con quell'istruzione...
anziche' "anomala" cmq io preferisco "non proprio intuitiva",
infatti il senso dovrebbe essere: assegno al puntatore f_s
il valore restituitomi dal costruttore della classe...
| Una curiosità ... in C mi sembra che le cose siano diverse (+ pulite)...
| com'è la sintassi di creazione ?
in C non ci sono classi, quindi .. ;)
io ho usto c++ a scuola, pero' in pratica
l'abbiamo usato come fosse C (fatta eccezione
per alcune features, ma cmq niente classi :( )
sto pero' usando/studiando c++ ('C con classi' ;) a tempo perso
per i cavoli miei e la sintassi è cosi':
classe istanza;
ovvero basta dichiararla...
(in qualsiasi punto del codice)
mentre in C++Builder per creare oggetti VCL
e' molto simile a delphi e sei obbligato ad
usare una sintassi simile utilizzando new:
Tbutton  *oggettoCreato = new Tbutton(this);
adesso spero vivamente di non aver detto ca##ate,
e se qualche c++ista passa di qui per caso
sono dispostissimo alle correzioni!
Ciao!
Alan Solo

 quindi anche il primo va ed è sintatticamente corretto.
No, sono due cose diverse.
Nel "primo" chiami il metodo Create di un oggetto non istanziato il che è
sbagliato e ad alto rischio di Access Violation...
Con il costrutto with puoi evitare di usare una variabile di tipo
TFileStream in cui memorizzare l'indirizzo dell'oggetto che hai creato ma,
come correttamente hai fatto, chiami il costruttore della classe e non di un
oggetto non istanziato.
Ciao :-)
--
Andrea Magni
E-Mail: 
ama...@interac.it

"Antonio Tarolla":
| > Provalo, e soprattutto trovami una
| > risposta a questo dilemma che non ha alcun senso! :)
|
| riguardo l'istruzione with, è logico che funziona ( il suo scopo, oltre a
| semplificare, è quello ) ed infatti sono pienamente d'accordo su quanto
| detto da Davide.
concordo
| Poi riguardo f_s.Create usato direttamente, non l'ho mai provato e per
| questo non mi sono sbilanciato più di tanto quando ho risposto alla
domanda.
| Insomma mi sono limitato a dire che la nostra inizializzazione fosse "più
| carina" della sua visto che lui non lamentava difetti.
| Magari non da subito errore perchè il metodo "Create" non è una normale
| procedura, ma un costruttore ed ora non so che privilegi abbia, ma
| sicuramente qualcuno di più rispetto ad un normale metodo.
si', avevo pensato pure questa, ovvero che essendo un costruttore
*forse* la si puo' richiamare ugualmente (?) pero' la cosa
strana e' che si puo' (io almeno) accedere a tutti i metodi e proprieta'!
| Poi non ho fatto altre prove, anche perchè io ritengo esatta e più
elegante
| ( e pure più logica ) la nostra ( e classica ) inizializzazione.
si', su questo non ci sono dubbi ;)
Ciao!
Alan Solo


Hai ragione, avevo letto male il codice di giorgio.
mea culpa
Ciao
Ruggero


per la precisione, in c++ (qualunque) puoi scrivere
classe* istanza = new classe; // se c'è il costruttore di default
oppure, per esempio:
classe* istanza = new classe(par1, par2);
il costrutto che hai nominato non lo conosco nel dettaglio (nel senso che
non lo ho mai provato), ma vuole solo dire che viene creato dinamicamente un
oggetto di nome oggettoCreato, di tipo TButton, passando come parametro al
costruttore il puntatore alla classe attuale (this). Tale oggetto può essere
liberato eseguendo
delete oggettoCreato;
Non si tratta affatto di un costrutto <specifico> di C++Builder o di VCL. E'
standard.

 wrote in message
hUgA5.20627$3R6.4...@news.infostrada.it...


"GioF"
| il costrutto che hai nominato non lo conosco nel dettaglio (nel senso che
| non lo ho mai provato), ma vuole solo dire che viene creato dinamicamente
un
| oggetto di nome oggettoCreato, di tipo TButton, passando come parametro al
| costruttore il puntatore alla classe attuale (this).
grazie per le precisazioni,
se posso pero' vorrei dare una mia "interpretazione":
viene dichiarato un puntatore alla classe TButton
(TButton*) di nome oggettoCreato il quale viene inizializzato
con il puntatore all'oggetto di classe TButton
creato dinamicamente passando ....
| Non si tratta affatto di un costrutto <specifico> di C++Builder o di VCL.
E'
| standard.
lo so, solo che non lo si puo dichiarare semplicemente cosi'
TButton oggettoCreato;
ma il compilatore di C++Builder ti da l'errore
"VCL style classes must be constructed using operator new"
e quindi *must* usare new ;)
e non ho capito perche' questa 'limitazione' bohhh...
Ciao, :)
Alan Solo

"Alan Solo":
| "VCL style classes must be constructed using operator new"
| e quindi *must* usare new ;)
| e non ho capito perche' questa 'limitazione' bohhh...
scusa, mi rispondo da solo, :)
forse perche' i costruttori delle classi VCL
hanno sempre un parametro da passargli
(Owner deve essere sempre specificato)...
credo sia cosi'... (?)

"GioF":
| non è lecita. se non ti ha dato un access violation vuol solo dire che sei
| stato fortunato.
| Per di più, se il costruttore create istanzia memoria dinamica, ad esempio
| con un GetMem, come fai a distruggerlo e a liberare la memoria?
con chi stai parlando? se stai parlando con me ti do ragione
(ovvero bug(?) di Delphi 4?...)
se invece parli con Ruggero (hai risposto al suo messaggio):
| > In realtà una cosa di questo tipo è lecita
| > with TFileStream.create(OpenDialog1-fileName, fmOpenRead) do begin
| >   seek(0,0);
| >   read(buffer,size);
| >   free;
| > end;
secondo me invece *e'* lecita come dice Ruggero...
ps: quota un po' meglio, tnx ;)


    Vediamo di capirci...
    Il compilatore di C++ Builder pretende che tu costruisca un oggetto in
memoria utilizzando i puntatori (quello che fai tu) perché in questo modo il
compilatore riesce ad ottimizzare molto bene il codice, l'altra alternativa
è il costrutto
    TButton Pippo(Self)
    che prevede l'associazione della variabile Pippo (e non di un puntatore
di riferimento all'oggetto TButton di nome Pippo) ad un oggetto TButton.
    Per quanto riguarda il parametro Owner, presente sia in Delphi che in
C++ Builder su tutte le classi della VCL, è una definizione imposta da
Borland (e non standard). In pratica ogni volta che si fissa l'owner si
responsabilizza l'oggetto possessore per la distruzione dei figli!
    Nel tuo esempio, quando usi This ( Self per Delphi ) e magari stai
definendo un metodo della classe di una Form, dichiari come possessore del
bottone la form e non dovrai preoccuparti di liberarne la memoria, perché ci
penserà la Finestra stessa a eliminare i sui Figli (cioè anche il bottone!)
    Saluti!
_________________________________
Gian Luca Dalla Torre
E - Mail: 
gianluca....@casteo.net
_________________________________

"Gian Luca Dalla Torre":
| > scusa, mi rispondo da solo, :)
| > forse perche' i costruttori delle classi VCL
| > hanno sempre un parametro da passargli
| > (Owner deve essere sempre specificato)...
| >
|
|     Vediamo di capirci...
|
|     Il compilatore di C++ Builder pretende che tu costruisca un oggetto in
| memoria utilizzando i puntatori (quello che fai tu) perché in questo modo
il
| compilatore riesce ad ottimizzare molto bene il codice, l'altra
alternativa
| è il costrutto
|
|     TButton Pippo(Self)
|
|     che prevede l'associazione della variabile Pippo (e non di un
puntatore
| di riferimento all'oggetto TButton di nome Pippo) ad un oggetto TButton.
scusami, ma
TButton Pippo(this);
non funziona, e il compilatore dice che per creare oggetti VCL
bisogna *perforza* usare new (BCB 5 Ent.) .. non so cosa dirti...
mi spieghi cmq la differenza che ci sarebbe con una dichiarazione
di quel tipo (ovvero senza new)?
Da quello che ho capito da cio' che hai detto viene
associata una variabile ad un oggetto TButton,
Ma cosa vuol dire? Vuoi dire che non e' un puntatore? Cos'e' allora?
(scusami ma C++/C++Builder non lo uso molto,
anzi diciamo pure che ho appena cominciato...)
|     Per quanto riguarda il parametro Owner, presente sia in Delphi che in
| C++ Builder su tutte le classi della VCL, è una definizione imposta da
| Borland (e non standard). In pratica ogni volta che si fissa l'owner si
| responsabilizza l'oggetto possessore per la distruzione dei figli!
|
|     Nel tuo esempio, quando usi This ( Self per Delphi ) e magari stai
| definendo un metodo della classe di una Form, dichiari come possessore del
| bottone la form e non dovrai preoccuparti di liberarne la memoria, perché
ci
| penserà la Finestra stessa a eliminare i sui Figli (cioè anche il
bottone!)
ok, grazie sapevo gia' il ruolo dell'owner,
sono un pivello con C++Builder, ma con Delphi
non sono proprio a questi livelli! ;)
Ciao!
Alan Solo


Ciao


si, ma non credo che sia SOLO per questo. Come ti ho scritto nel post
precedente, credo che sia perché devono essere istanziati a run-time e che
sia l'architettura win32 a richiederlo.

quindi anche il primo va ed è sintatticamente corretto.
Il primo non va e basta :-)
f_S e' di tipo TFileStream, come la usi se non e' ancora allocata?
Con "with TFileStream.Create(..) " crei una variabile anonima, ma
sempre a partire dal costruttore della classe
Ciao
--
Piero Bonanno
bop...@libero.it
pie...@tiscalinet.it
bop...@tin.it
bpie...@hotmail.com
______________________________________________
"Madame, lei ha tra le gambe uno strumento
che puo' offrire piacere a migliaia di persone,
e tutto quello che sa fare e' grattarlo"
- Sir Thomas Beechan a una violoncellista

    Allora, vediamo di spiegarti meglio il concetto di C++ per quanto
riguarda gli oggetti in memoria.
    Quando tu dichiari in C++ un tipo più l'asterisco dichiari un puntatore
all'oggetto (l'equivalente di ^ per Delphi). Un puntatore non è altro che un
riferimento (al suo interno c'è un indirizzo di memoria) che punta all'area
di memoria che contiene effettivamente l'oggetto. Quando tu utilizzi new non
fai altro che creare un'istanza dell'oggetto e immettere l'indirizzo di
memoria nel puntatore. Questo approccio è molto più potente rispetto
all'altro che ti spiegherò fra poco perché permette l'utilizzo
dell'aritmetica dei puntatori (argomento un po' complesso da spiegarti su
due piedi ma molto potente se hai C++) e ha il vantaggio - svantaggio di
delegare la gestione dell'oggetto in memoria al programmatore; questo vale a
dire che se ti dimentichi di usare Delete o chiamare il distruttore della
classe e perdi il riferimento all'oggetto (perché sposti il puntatore)
quell'area di memoria non sarà più disponibile fino al riavvio successivo
della macchina.
    Il secondo costrutto che ti ho fatto vedere invece dichiara una
variabile di tipo dell'oggetto e quindi non hai un puntatore all'oggetto ma
un'istanza già inizializzata dell'oggetto stesso. La si utilizza a tutti gli
effetti come se fosse un oggetto ( si utilizza . al posto di ->) e non devi
preoccuparti di distruggere l'istanza perché se ne occupa il compilatore,
appena esce dallo scope essa viene distrutta. Quindi è un onere per il
compilatore che deve controllare fino a quando la utilizzi ed è per questo
che C++ Builder ti rompe le scatole.


"Gian Luca Dalla Torre":
[...]
| questo vale a
| dire che se ti dimentichi di usare Delete o chiamare il distruttore della
| classe e perdi il riferimento all'oggetto (perché sposti il puntatore)
| quell'area di memoria non sarà più disponibile fino al riavvio successivo
| della macchina.
ok, ho capito, ma nel caso di oggetti vcl, questi verranno comunque
distrutti dall'owner, giusto?
|     Il secondo costrutto che ti ho fatto vedere invece dichiara una
| variabile di tipo dell'oggetto e quindi non hai un puntatore all'oggetto
ma
| un'istanza già inizializzata dell'oggetto stesso. La si utilizza a tutti
gli
| effetti come se fosse un oggetto ( si utilizza . al posto di ->) e non
devi
| preoccuparti di distruggere l'istanza perché se ne occupa il compilatore,
| appena esce dallo scope essa viene distrutta. Quindi è un onere per il
| compilatore che deve controllare fino a quando la utilizzi ed è per questo
| che C++ Builder ti rompe le scatole.
ok, grazie adesso ho capito la differenza delle dichiarazioni,
e anche il perche' C++Builder s'incacchia, adesso aggiungo anche
*giustamente* :)
Grazie di nuovo
Ciao,
Alan Solo