[VB6] Gestione specifiche import-export di database Access
Pubblicato da Mario De Ghetto su 15 Febbraio 2008
Per il mio lavoro, spesso ho la necessità di gestire l’importazione e l’esportazione di file di dati (tipicamente file di testo con record a lunghezza fissa) da Microsoft Access. Per queste attività ho sempre utilizzato la gestione delle specifiche di importazione/esportazione nativa di Access, ma è una funzionalità che non mi ha mai soddisfatto completamente.
Per esempio ci sono stati dei casi in cui non sono riuscito a modificare una specifica già esistente e ho dovuto ricrearla da zero, senza contare il problema di inserire un campo all’interno di una specifica già esistente: in questo caso è necessario ricalcolare manualmente il carattere di partenza di ciascun campo successivo. Anche lo spostamento di un campo in una diversa posizione è un’attività che può diventare un’atroce perdita di tempo.
Ecco quindi che, diverso tempo fa, ho pensato di creare un progetto in Visual Basic 6.0 (download di 153 kb). Anzi, i progetti sono più di uno:
-
un progetto che comprende l’interfaccia principale (ImportExport.vbp)
-
un progetto che comprende l’interfaccia per la gestione delle specifiche (Specifiche.vbp)
-
un progetto per gestire le attività di importazione (Import.vbp)
-
un progetto per gestire le attività di esportazione (Export.vbp).
Con il link sopra riportato potete scaricare tutti questi progetti, con anche gli eseguibili già compilati, un database di prova e alcuni file di testo, con qualche specifica di importazione/esportazione già caricata.
Le specifiche, infatti, vengono caricate in una tabella di Access. E’ possibile estrarre anche le specifiche da un database già esistente e salvarle in questa tabella speciale, così da centralizzare tutte le attività di importazione/esportazione.
Non è tutto: considerato che potrebbe essere necessario eseguire un’importazione/esportazione anche direttamente da un programma VBA scritto all’interno di Access (o di un altro prodotto Office) o perfino in un proprio programma scritto in qualsiasi altro linguaggio (perfino VB.NET), ho pensato di gestire i parametri della riga di comando utilizzati per avviare i programmi Import.exe e Export.exe.
In questo modo è possibile avviare, per esempio, Import.exe passandogli già i parametri necessari per eseguire l’importazione senza nemmeno aprire la sua interfaccia grafica! Il trucco sta tutto nell’evento Load del form Import.frm:
Private Sub Form_Load()
ReDim argv(5) As String
Dim i As Integer
Dim sNomeFile
Dim sNomeSpecifica
Dim sNomeDB
Dim sNomeTabella
' legge la riga di comando:
argv = GetCommandLine(argv)
If argv(1) <> "" Then
' i parametri vengono passati secondo quest'ordine:
sNomeFile = argv(1)
sNomeSpecifica = argv(2)
sNomeDB = argv(3)
sNomeTabella = argv(4)
sFlagDelete = argv(5)
If argv(5) = 1 Then
Call DeleteTable(sNomeDB, sNomeTabella)
End If
If argv(1) <> "" Then
Call ImportaFile(sNomeFile, sNomeSpecifica, sNomeDB, sNomeTabella)
End If
' annulla il caricamento del form:
Unload Me
Exit Sub
End If
ReDim arraySpecifiche(1)
arraySpecifiche = ElencaSpecifiche()
Me.txtNomeSpecifica.Clear
For i = 1 To arraySpecifiche(0)
Me.txtNomeSpecifica.AddItem arraySpecifiche(i)
Next i
End Sub
Per ultima, una piccola precisazione: questo programma l’ho scritto qualche anno fa, ma non l’avevo mai pubblicato prima, quindi è una soluzione assolutamente inedita.
Può sembrare anacronistico un progetto scritto in VB6 come nuova soluzione, visto che ormai .NET è diventata la piattaforma di sviluppo prevalente, ma c’è una considerazione da tenere presente: tra i file forniti con il file compresso c’è anche un report dell’analisi eseguita con Code Advisor per verificare la compatibilità dei progetti con VB.NET. L’esito è assolutamente confortante, dato che viene segnalato solo un piccolo problema relativo a Option Explicit, facilmente eliminabile.
Ovviamente questo progetto può essere utilizzato come prototipo per realizzare una soluzione analoga e più orientata agli oggetti, utilizzando codice VB.NET puro.
In ogni caso spero che possa essere utile a chi, come me, ha avuto problemi nell’utilizzo delle funzionalità native di Access per la gestione delle specifiche di importazione/esportazione.
Andrea detto
Ciao Mario grazie mille per la tua segnalazione sul mio blog! un grosso saluto e buon lavoro
Andrea
Giovanni Puglisi detto
Ho letto l’articolo e scaricato i file. Premetto che uso Windows Vista e Access2007. Dagli eseguibili, quando clicco sul pulsante “Carica specifica da database” dal form “Specifiche” non succede nulla. La mia necessità è quella d’importare dei files di testo che contengono dati con campi delimitati; le colonne contengono in modo disomogeneo dati che ho necessità d’importare in un’unica tabella già definita. Per essere più chiaro faccio un esempio:
file1.txt
data; ora; durata; campo da saltare; chiamante; campo da saltare; chiamato; … campo …;
file2.txt
ora; data; campo da saltare; chiamato; chiamante; campo da saltare; … campo …;
i dati dovrebbero confluire nella tabella con la seguente definizione:
data ora durata chiamante chiamato.
Visto che è richiesto un commento non so se sia il posto giusto per la mia richiesta, per il momento ringrazio ugualmente per l’aiuto e per la presenza di siti come questo che tanto supportano i principianti e gli esperti in cerca di spunti utili.
Grazie.
Giovanni
Mario De Ghetto detto
Normalmente l’importazione di file di testo avviene con un “tracciato record” ben definito e quindi anche l’ordine dei campi dovrebbe essere sempre lo stesso.
Certamente possono essere fatte delle manipolazioni, utilizzando una tabella di appoggio e quindi adattando i dati importati alla tabella di destinazione.
Se la prima riga del file contiene i nomi dei campi, si potrebbe importare il file in un foglio Excel (magari con l’”automazione di Excel”) e poi da questa importare in una tabella di Access, ma è importante che i nomi dei campi siano sempre uguali, altrimenti bisogna comunque intervenire modificandoli sempre con l’automazione o manualmente.
La cosa migliore, comunque, è sempre quella di imporre a chi produce i file di mantenere sempre la stessa struttura (tracciato record), perché normalmente lo scambio avviene con un formato definito a priori.
Per quanto riguarda Access 2007: non l’ho ancora utilizzato ma lo farò tra breve, in quanto ho iniziato un nuovo libro che tratterà argomenti relativi ai database, con alcuni esempi in Visual Basic 2008 (quindi non VB6…).
Può darsi che Access 2007 abbia una gestione delle specifiche di import/export diversa dalle versioni precedenti. Se così è, vedrò di esaminare anche questa problematica e di pubblicare un articolo per spiegare come si risolve il problema.
Ultimo commento: se devi risolvere il problema in VB6, temo di deluderti, perché alcuni mesi or sono ho deciso di non supportare più codice VB6, perché ormai è un linguaggio e un ambiente non più supportato dalla stessa Microsoft, quindi senza più alcuna prospettiva di evoluzione e di miglioramento. Infatti in questo blog ho pubblicato, in seguito, solo articoli e notizie su VB.NET e C#, oltre ad altre tecnologie correlate.
Giovanni Puglisi detto
Intanto grazie per la risposta. Riscrivo per far conoscere la soluzione che ho trovato, non utilizzando VBA ma VB.Net, grazie anche al contenuto del Suo libro “Visual Basic 2008 spiegato a mia nonna”. Di seguito riporto il codice:
Imports System.IO
Imports System.Collections.ArrayList
Public Class Form1
Dim nuovoArray = New ArrayList
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim archivio As String
Dim i As Integer
Dim linea As String
Dim lista = New ArrayList()
Dim destinazione As String
archivio = "C:\fileditesto.txt"
destinazione = "C:\temp.txt"
'Verifico se il file esiste. Se è vero lo elimino
If File.Exists(destinazione) Then
File.Delete(destinazione)
End If
FileOpen(1, archivio, OpenMode.Input) 'apro in input il file di testo
FileOpen(2, destinazione, OpenMode.Output) ' creo un nuovo file di destinazione
While Not EOF(1) 'ciclo fino alla fine del file
linea = LineInput(1) 'leggo una riga
If linea = "" Or linea = Chr(12) Then ' rimuovo tutte le righe vuote e le interruzioni di pagina
lista.Remove(linea)
End If
lista.Add(linea) 'aggiungo all'arraylist la riga
End While
Dim testo As String
testo = ""
For i = 13 To lista.Count - 58 ' leggo le righe che m'interessano eliminando quelle all'inizio e alla file
testo = testo & lista(i) & Chr(13)
Next i
PrintLine(2, testo) 'scrivo i nuovi risultati nel file di destinazione
FileClose(1) 'chiudo i files
FileClose(2)
Dim destinazione2 As String 'Creo la variabile che conterrà il percorso del file definivo
destinazione2 = "C:\NuovoFileTesto.txt"
'Verifico se il file esiste. Se è vero lo elimino
If File.Exists(destinazione2) Then
File.Delete(destinazione2)
End If
FileOpen(1, destinazione, OpenMode.Input) 'Apro il nuovo file prodotto prima
FileOpen(2, destinazione2, OpenMode.Output) 'Preparo il file per l'output
Dim rigo As String
While Not EOF(1) 'ciclo fino alla fine del file
rigo = LineInput(1) 'leggo una riga
If rigo = "" Or rigo = Chr(12) Then 'elimino righe vuote e interruzioni di pagina se esistono
lista.Remove(rigo)
End If
nuovoArray.Add(rigo) 'aggiungo alla lista la riga
End While
FileClose(1)
Dim righeOrdinate As String ' creo una variabile che conterrà tutto il testo della nuova tabella prodotta dal nuovo output con le colonne ordinate come desiderato
& Chr(10) ' richiamo la funzione OrdinaCampi
righeOrdinate = ""
Dim b As Integer
For b = 1 To nuovoArray.Count - 1
righeOrdinate = righeOrdinate + OrdinaCampi(destinazione, b, 1, 10) & " " & OrdinaCampi(destinazione, b, 12,
Next b
PrintLine(2, righeOrdinate) ' stampo i risultati
FileClose(2) ' chiudo il file
Kill(destinazione) 'elimino il file intermedio
End Sub
Function OrdinaCampi(ByVal archivio As String, ByVal nRiga As Integer, ByVal colonna As Integer, ByVal larghezza As Integer) As String
Dim riga As String
'Dim nuovoArray As New ArrayList
Dim campo As String
FileOpen(1, archivio, OpenMode.Input)
campo = ""
While Not EOF(1) 'ciclo fino alla fine del file
riga = LineInput(1) 'leggo una riga
nuovoArray.Add(riga) 'aggiungo alla lista la riga
End While
If nRiga > 0 Then
campo = nuovoArray(nRiga - 1)
If larghezza > 0 Then
campo = campo.Substring(colonna - 1, larghezza).TrimEnd
End If
FileClose(1)
Return (campo)
End If
End Function
Per arrivare a questo codice mi sono avvalso molto anche di quanto contenuto nella pagina internet: