Usare files di testo come DataBase

 

A completamento di quanto abbiamo appena detto continuerò col presentare alcune metodologie per creare, aggiornare e leggere file di testo viste da un'altra angolazione.

Alcune delle operazioni possibili sono:

Per fare questo dobbiamo familiarizzare con le nuove operazioni di apertura e chiusura dei files usando l'istruzione "Open". Questa istruzione ci permette di eseguire operazioni di Input / Output su file.

Le modalità che vedremo oggi sono:

Per quanto riguarda queste tre modalità che useremo con "Open" c'è da aggiungere che:

Per mettere subito al lavoro le routines che vi presenterò vi mostro anche come ho preparato il foglio che ho deciso di torturare. Notate la prima riga lasciata vuota per gli usi che ci potrebbero venire in mente (intestazioni, pulsanti e quanto altro).

Attenzione: i nomi e relativi indirizzi sotto elencati, come già ricordato in altre circostanze analoghe, sono stati opportunamente manipolati per renderli inservibili per eventuali ricerche e violazione della privacy. Se nel caso molto improbabile si dovesse riscontrare una qualche somiglianza a dati reali (potrebbe succedere soprattutto negli abbinamenti Nome - Cognome) la cosa è puramente casuale.

 

  A B C D E F G
1              
2 ID Cognome Nome INDIRIZZO CAP CITTA' PROV
3 1 Migliavacca Luigi VIA P. FIMIANI-LOC.TRIVIO 35031 Varena FR
4 2 Liberali Franca VIA DEL TUSCOLANO 1 67030 Calcinatello BO
5 3 Di Maggio Mario TERMINAL CONTENITORI MOLO VI 48012 Verzegnis AL
6 4 Scicchitano Andrea VIA SABIN, 34/2 10060 Peri NA
7 5 Maggi Massimo VIA DEL TUSCOLANO 1 20070 Formignana VI
8 6 Edelvisi Maurizio VIA MATTEO RICCI 12 53040 Roasio VA
9 7 Gerardini Silvano Z.I SAMBUCETO 61040 Villaretto Chisone LC

Siccome in tutte le routines che qui andrò a presentare ci sono delle istruzioni che si ripetono sempre, per facilitare la lettura e la comprensione delle stesse, ho pensato di:

Queste istruzioni si possono mettere all'inizio del modulo dove si andranno a scrivere le routines di lettura / scrittura del file.

E' quindi ovvio che le dichiarazioni delle variabili che debbono essere rese pubbliche andranno sistemate nella parte alta del modulo, al di fuori di qualsiasi altra routine.

 

Allora qui vediamo le variabili pubbliche e la routine alla quale si rifanno le altre routine che seguiranno

Dim DestFile, Cartella, FileNum, NomeFile


Sub Comuni()
NomeFile = "archivio.txt"
Cartella = ThisWorkbook.Path & "\"
DestFile = Cartella & NomeFile
FileNum = FreeFile()
End Sub

 

Creare di un file di testo vuoto

Il caso più semplice è senz'altro la creazione del file di testo vuoto. La routine che andremo a scrivere si limita semplicemente ad aprire e quindi chiudere il file.

Con questa routine si può verificare uno dei seguenti casi:

Sub creaArchivio()
' si va ad inizializzare le variabili che ci serviranno per eseguire il lavoro
Comuni
' viene aperto il file in modalità SCRITTURA
' se il file non esiste viene semplicemente creato
' se il file esiste già viene semplicemente aperto e chiuso
' ma attenzione: se contiene dei dati questi verranno distrutti

Open DestFile For Output As #FileNum
Close #FileNum
End Sub

 

Creare un file di testo coi dati

La seguente routine compierà a grosse linee le stesse operazioni appena viste ma nello stesso tempo scriverà nel file anche le informazioni che gli manderemo.

Tuttavia comincia a farci porre il problema su come scrivere nel file i nostri dati. Infatti dobbiamo anche tener conto che in qualche modo dobbiamo rileggere questi dati.

Il problema da tener presente è come distinguere i vari elementi in fase di lettura.

Con che criterio potremmo separare i vari elementi quando andremo a leggere una stringa come questa?

1 Borsotti Massimo VIA PO, 31 02040 Africo CN

Per separare i vari elementi potremmo basarci sul carattere separatore SPAZIO. Ma osservando meglio la stringa notiamo che gli spazi sono presenti anche all'interno di certi elementi "VIA PO, 31".

Perciò è necessario che nel progettare la nostra routine dobbiamo tener presente anche questo problema.

Il carattere che più comunemente ci viene in mente potrebbe essere l'asterisco "*". Sarà quindi a questo carattere che nella seguente routine e in quelle che seguiranno porremo la nostra attenzione per ottenere, nel file di testo, una cosa del genere:

1 *Borsotti*Massimo*VIA PO, 31*02040*Africo*CN

Sub creaArchivio2()
Dim Uriga, UColonna
Dim A, B
Sheets("Foglio1").Select
' vado ad inizializzare le variabili che mi serviranno
Comuni
' determino i limiti dell'intervallo che debbo registrare nel file di testo
Uriga = Range("A3").End(xlDown).Row
UColonna = Range("A3").End(xlToRight).Column
' inizia la procedura di apertura del file per la scrittura dei nostri dati
Open DestFile For Output As #FileNum
' i nostri dati nel file di testo
For A = 3 To Uriga
For B = 1 To UColonna
' il ; (punto e virgola) posto dopo la seguente istruzione evita
' che la scrittura avvenga sulla riga successiva

Print #FileNum, Cells(A, B);
' il ciclo "For A" scorre il contenuto del foglio lungo le righe
' il ciclo "For B" scorre il contenuto del foglio lungo le colonne
' quando quest'ultimo ciclo si trova alla fine è inutile, se non
' dannoso, scrivere il carattere separatore

If B <> UColonna Then
Print #FileNum, "*";
End If
Next
' usciti da questo ciclo "For B" dobbiamo cambiare riga
' per fare questo è sufficiente una istruzione "Print #FileNum,"
' senza argomenti e senza il ; (punto e virgola) finale

Print #FileNum,
Next
' usciti anche da questo ciclo "For A" abbiamo finito il nostro
' lavoro chiudiamo perciò il canale di comunicazione col file
' aperto precedentemente

Close #FileNum
End Sub

 

Aggiornamento del file di testo

Ma il lavoro non finisce qui. Dopo la prima registrazione dei nostri dati potremmo avere esigenza di aggiornare il nostro archivio.

Possiamo agire in tre maniere diverse.

  1. Alla fine del lavoro vogliamo registrare tutti i nostri dati (i vecchi dati ed i nuovi)
  2. Vogliamo aggiungere all'archivio già esistente solo i nuovi dati durante l'inserimento
  3. Vogliamo aggiungere i nuovi dati nel file solo alla fine del lavoro

Registrare tutti i nostri dati alla fine del lavoro

In questo caso possiamo usare la stessa routine appena vista. Ma, in questo caso, occorre che tutti i dati siano in qualche modo reperibili: o sul foglio di Excel (come nostra abitudine) o in una matrice. Detto questo non c'è altro da aggiungere se vogliamo usare questa metodologia.

Aggiungere all'archivio solo i dati dell'ultimo inserimento

Questa opportunità ci può tornare utile nel caso che per economia di spazio e, soprattutto di memoria, durante il lavoro non carichiamo tutto l'archivio.

In questo caso per aggiungere nel nostro file i nuovi dati apriamo il file in modalità "Append".

I dati che vogliamo scrivere nel nostro file si troveranno a seconda della metodologia che stiamo usando nel nostro applicativo:

Penso non sia un problema rilevare di volta in volta il dato che vogliamo trasferire nel file:

Quindi basta sostituire la sintassi giusta lì dove leggeremo: "Print #FileNum, Cells(URiga, B);"

Detto questo possiamo passare ad esaminare la routine costruita usando la modalità "Append".

Noterete senz'altro l'affinità di questa routine con quella precedente per cui i commenti saranno molto sobri.

Sub aggiornaArchivio1()
Dim Uriga, UColonna, B
Sheets("Foglio1").Select
Comuni
' leggiamo i valori dell'ultima riga della tabella da cui stiamo attingendo
Uriga = Range("A3").End(xlDown).Row
UColonna = Range("A3").End(xlToRight).Column
Open DestFile For Append As #FileNum
' URiga è la riga del foglio di Excel in cui è avvenuto l'ultimo inserimento
' è da questa riga che leggeremo i dati da scrivere nel file

For B = 1 To UColonna
Print #FileNum, Cells(Uriga, B);
' dopo ogni dato, sulla stessa riga, il carattere separatore tra i vari elementi
If B <> UColonna Then
Print #FileNum, "*";
End If
Next
' si cambia riga
Print #FileNum,
Close #FileNum
End Sub

Aggiungere i nuovi dati nel file alla fine del lavoro

Potremmo trovarci in una delle seguenti situazioni.

  1. abbiamo a disposizione (sul foglio di Excel o nella matrice) solo i nuovi dati perchè forse non avevamo bisogno di quelli vecchi o perchè abbiamo provveduto di memorizzare in un'altro intervallo del foglio di Excel o in un'altra matrice i nuovi dati
  2. abbiamo a disposizione (sul foglio di Excel o nella matrice) tutti i dati: quelli già precedentemente registrati e quelli nuovi

Nel primo caso possiamo adattare la routine esposta nel paragrafo "Creare un file di testo coi dati" avendo cura di sostituire l'istruzione: "Open DestFile For Output As #FileNum" con la nuova istruzione: "Open DestFile For Append As #FileNum"

Nel secondo caso l'operazione risulta leggermente più complessa.

 

Per compiere con successo l'operazione eseguiamo le operazioni che seguono.

Sub aggiornaArchivio2()
Dim Uriga, UColonna, NumElem, Arch, MioDato, Riga, A, B
Sheets("Foglio1").Select
Comuni
Uriga = Range("A3").End(xlDown).Row
UColonna = Range("A3").End(xlToRight).Column
' tenendo conto che i dati sulla tabella con cui sto lavorando
' iniziano dalla 3^ riga determiniamo il numero di record
' ricorrendo al seguente calcolo
' questo dato ci occorre per determinare se è necessario
' effettuare l'aggiornamento e da quale riga iniziare

NumElem = Uriga - 2
' ora ci apprestiamo ad aprire il nostro file in modalità lettura
' solo per contare i record in esso contenuti

Open DestFile For Input As #FileNum
Arch = 0
Do While Not EOF(1)
' il dato che leggiamo in questa fase non ci serve per cui ci
' limitiamo semplicemente a leggerlo

Line Input #1, MioDato
' ad ogni lettura incrementiamo solo il nostro contatore
Arch = Arch + 1
Loop
Close #FileNum
MsgBox "Record presenti in archivio = " & Arch & vbCr _
& "Dati presenti sul foglio = " & NumElem
' a questo punto abbiamo sia il numero di record presenti
' nel foglio sia quello dei record registrati
' siamo pronti per decidere se aggiornare l'archivio o no
' abbiamo il numero di record residenti sul foglio di Excel
' abbiamo il numero di record residenti nel file

If NumElem > Arch Then
Riga = Arch + 3
MsgBox "Necessario aggiornare archivio" & vbCr _
& "a partire dalla riga " & Riga & " del foglio"
' se è necessario eseguire l'aggiornamento dell'archivio
' apriamo il file in modalità "Append"

Open DestFile For Append As #FileNum
' scriviamo nel file solo i nuovi dati
For A = Riga To Uriga
For B = 1 To UColonna
Print #FileNum, Cells(A, B);
If B <> UColonna Then
Print #FileNum, "*";
End If
Next
Print #FileNum,
Next
Close #FileNum
Else
MsgBox "Aggiornamente non necessario"
End If
End Sub

 

Lettura del file di testo

Per la lettura del file tra le varie procedure e metodi, per la sua semplicità, scelgo la lettura sequenziale del file leggendo uno alla volta l'intera riga. Questa è la routine utilizzata.

Prevedo la scrittura dell'archivio in un foglio di Excel. Ma, come già sappiamo, possiamo uscire in altre locazioni come in una UserForm opportunamente preparata o in una matrice. Basta solo intervenire nell'istruzione: ".Cells(Arch + 1, Col) = Elem(A)" o ".Cells(Arch + 1, 1) = MioDato".

Nella routine ho previsto sia la visualizzazione dell'intera stringa prelevata (Record) sia la visualizzazione dei singoli elementi (Campi).

Sub leggiArchivio()
Dim Arch, MioDato, Elem, NumElem, Col, A
Comuni
On Error Resume Next
Open DestFile For Input As #FileNum
If Err <> 0 Then
MsgBox "Impossibile aprire il file " & DestFile & vbCr _
& Error(Err)
End
End If
On Error GoTo 0
Arch = 1
With Sheets("Foglio3")
.Cells.ClearContents
Do While Not EOF(1)
' leggo l'intera riga registrata nel file
Line Input #FileNum, MioDato
' utilizzando il carattere delimitatore "*" suddivido l'intera stringa letta
' nei vari elementi di cui la stringa è composta e li depongo nella matrice "Elem"

Elem = Split(MioDato, "*")
NumElem = UBound(Elem)
' spetta all'utilizzatore finale scegliere se utilizzare l'intera stringa
' come qui mostrato

.Cells(Arch + 1, 1) = MioDato
' oppure i singoli elementi come mostrato qui di seguito
Col = 2
For A = LBound(Elem) To UBound(Elem)
.Cells(Arch + 1, Col) = Elem(A)
Col = Col + 1
Next
Arch = Arch + 1
Loop
End With
Close #FileNum
Arch = Arch - 1
End Sub

 

Il test per verificare l'esistenza del file

Se lo riteniamo opportuno, all'inizio delle routines appena descritte, specialmente quelle che riguardano gli aggiornamenti, possiamo anche fare un test per verificare l'esistenza del file di testo.

Per eseguire il test utilizzo la possibilità che il VBA ci offre di controllare gli errori. Quindi tra le tre modalità sin qui osservate scelgo quella che è capace di restituirmi un errore nel caso il file non venisse trovato ed è la modalità "Input".

In questa procedura quindi ci viene in aiuto la possibilità di gestire gli errori offertaci dal VBA. Per verificare la presenza o meno del file che stiamo cercando usiamo quindi, anche se in realtà vorremmo scrivere nel file, la modalità di lettura che sicuramente provocherà un errore nel caso il file non esistesse.

Sub aggiornaSe()
Dim Risposta
Comuni
On Error Resume Next
' apro il file di testo in lettura
Open DestFile For Input As #FileNum
If Err <> 0 Then
' se si verifica l'errore ....
Risposta = MsgBox(NomeFile & " non esiste, occorre crearlo ", vbYesNo + vbCritical)
If Risposta = vbNo Then Exit Sub
MsgBox "si esegue la creazione del file"
On Error GoTo 0
Close #FileNum
' ... mi comporto di conseguenza (è ovvio che tra quelle esposte non posso utilizzare
' la procedura di lettura del file)

creaArchivio ' dopo aver creato l'archivio vuoto posso usare uno dei seguenti metodi
aggiornaArchivio2
'aggiornaArchivio1
'creaArchivio2

End If
Close #FileNum
End Sub

 

Conclusioni

Usare questa metodologia ovviamente comporta dei vantaggi e degli svantaggi.

Secondo il mio modesto parere, mentre gli svantaggi si riducono nel prestare maggior attenzione nel preparare il lavoro in fase di progettazione, ben più numerosi sono i vantaggi che se ne possono ricavare.

Innanzitutto, specialmente se lavoriamo don DataBase di una certa corposità, alleggeriamo di molto il file di Excel che altrimenti dovrebbe contenere tutti i nostri dati nelle sue celle lasciando a questo solo il compito di elaborare i dati e mostrarci gli elaborati.

Se dobbiamo usare il codice per scrivere intestazioni, didascalie o altro, invece di riempire interi moduli di istruzioni per scrivere in numerose celle queste informazioni possiamo scrivere in un file di testo le due coordinate di riga e colonna ed il relativo messaggio.

Mi verrebbero in mente altre applicazioni che si potrebbero realizzare con questa tecnica, ma per ovvi motivi mi esimo dall'esporle in questa sede. Sta anche a chi legge ed è interessato scoprire i vari utilizzi di queste tecniche.

 

Non mi resta quindi che augurarvi buon lavoro e buon apprendimento.

Questo è il file col quale ho preparato il lavoro: file da scaricare