IMPORTATION D'UN FICHIER.TXT SERVANT DE MINI BASE DE DONNÉES (SÉPARATEURS ";") D
Cacophrene
Messages postés251Date d'inscriptionlundi 29 mars 2004StatutMembreDernière intervention 4 mars 2008
-
17 août 2006 à 09:41
jean_marc_n2
Messages postés170Date d'inscriptionjeudi 11 décembre 2003StatutMembreDernière intervention24 janvier 2009
-
20 août 2006 à 09:54
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.
jean_marc_n2
Messages postés170Date d'inscriptionjeudi 11 décembre 2003StatutMembreDernière intervention24 janvier 2009 20 août 2006 à 09:54
=> Inutile d'ajouter une variable pour retourner le nombre de lignes.
Au retour de la fonction, il suffit de faire:
Dim r As Boolean, szErr As String
Dim t() As String
Dim nb_lignes as long, nb_champs as long
r = ImportTxtFile("c:\test.dat", ";", t(), szErr, 1)
' RECUP NOMBRE LIGNES
nb_lignes = Ubound(t(), 1)
Tu peux aussi récupérer le nombre de champs:
nb_champs = Ubound(t(), 2)
gnieark
Messages postés53Date d'inscriptionjeudi 17 août 2006StatutMembreDernière intervention22 octobre 2010 20 août 2006 à 00:25
j'ai réussi à intégrer ta fonction dans mon code, ça y est!
gnieark
Messages postés53Date d'inscriptionjeudi 17 août 2006StatutMembreDernière intervention22 octobre 2010 19 août 2006 à 23:58
po mal merci.
pour la suite je vais tenter d'intégrer à ta fonction une variable contenant le nombre de lignes du texte.
Si j'y arrive pas j'appellerai à l'aide ;)
jean_marc_n2
Messages postés170Date d'inscriptionjeudi 11 décembre 2003StatutMembreDernière intervention24 janvier 2009 19 août 2006 à 10:50
Hello,
gnieark => Pour préserver ton tableau, il suffit que celui ci soit déclaré ailleurs que dans ta fonction.
VOici un exemple d'amélioration pour ta Sub:
- C'est maintenant une fonction qui retourne un booléen (True si tout va bien, False en cas d'erreur)
- Elle prend en paramètre le nom de fichier, le séparateur à utiliser, le tableau (qui sera alooué dynamiquement), une variable pour mettre le code d'erreur au cas ou (fichier non trouvé par exemple), et en option une variable permettant de commencer à remplir ton tableau à l'indice voulu (en général 0 ou 1).
Private Function ImportTxtFile(ByVal fileName As String, _
ByVal separator As String, _
ByRef tData() As String, _
ByRef errorString As String, _
Optional ByVal baseArray As Integer = 1) As Boolean
Dim f As Integer
Dim tLine() As String
Dim tSplit() As String
Dim buffer As String
Dim nbItem As Long
Dim i As Long, j As Long
On Error GoTo ImportTxtFile_ERR
f = FreeFile()
Open fileName For Binary As #f
buffer = Space$(LOF(f))
Get #f, , buffer
Close #f
tSplit() = Split(buffer, vbCrLf)
nbItem = UBound(Split(tSplit(0), separator)) + baseArray
ReDim tData(UBound(tSplit()) + baseArray, nbItem)
For i = LBound(tSplit()) To UBound(tSplit())
tLine = Split(tSplit(i), separator)
For j = LBound(tLine) To UBound(tLine)
tData(i + baseArray, j + baseArray) = tLine(j)
Next j
Next i
ImportTxtFile = True
ImportTxtFile_END:
Exit Function
ImportTxtFile_ERR:
errorString = Err.Description
Resume ImportTxtFile_END
End Function
Un exemple d'appel:
Private Sub Command2_Click()
Dim r As Boolean, szErr As String
Dim t() As String
r = ImportTxtFile("c:\test.dat", ";", t(), szErr, 1)
End Sub
Avantages:
- Tout est passé en paramètres, plus rien de hard-codé dans la "Sub"
- L'allocation du tableau est dynamique, aussi bien pour les lignes que pour les colonnes: tu peux lire n'importe quel fichier, de n'importe quelle taille, le code est toujours valable
- La lecture en bloc est très rapide
- C'est une vraie fonction, utilisable de façon autonome.
Au final, ça charge un fichier de 20000 lignes avec 7 champs par lignes en 0,4 seconde.
Bonne suite :-)
cs_asimengo
Messages postés280Date d'inscriptionjeudi 24 mars 2005StatutMembreDernière intervention18 mars 2009 18 août 2006 à 11:49
@Bouv: Je vais l'uploader dès que possible, mais il faudrait que je le retouche un peu, il s'agissait de ma première source et j'avais encore beaucoup à apprendre en VB.
Au fait vu ton niveau très appréciable pourras-tu me faire des remarques et suggestions pour son amélioration?
bouv
Messages postés1411Date d'inscriptionmercredi 6 août 2003StatutMembreDernière intervention 3 mars 20191 18 août 2006 à 11:26
Asimengo>>Interressant, mais j'aimerai en savoir plus sur la structure du fichier schema.ini
Dommage que ta source ne contienne pas de vrai zip avec un projet exemple.
cs_asimengo
Messages postés280Date d'inscriptionjeudi 24 mars 2005StatutMembreDernière intervention18 mars 2009 18 août 2006 à 11:02
@gnieark: Je t'expose ci-dessous l'utilisation de Microsoft Text Driver pour mieux faire ton importation. Tu récupères le fichier dans un recordset et il offre encore plus de possiblités. Ci-dessous un rapide aperçu de la démarche.
Dim Cnx As ADODB.Connection
Dim cmdadodb As ADODB.Command, sCommandText as string
Dim Rst as ADODB.Recordset
'Definition et ouverture de la Connexion
StrCnx = "driver={Microsoft Text Driver (*.txt; *.csv)};DriverId=27" & _
";DBQ=" & App.Path & "\DATA\ASCII" 'DBQ désigne le dossier où se trouve le fichier ASCII
Set Cnx = New ADODB.Connection
With Cnx
.ConnectionString = StrCnx
.Open
End With
'Définition de la commande, elle peut être une requête sur ton fichier Texte.
sCommandText = "[Mon fichier ascii.txt]" 'Ne pas oublier les crochets.
Set cmdadodb = New ADODB.Command
With cmdadodb
.ActiveConnection = Cnx
.CommandType = adCmdUnknown
.CommandText = sCommandText
End With
'Ma variable recordset Rst contiendra tout le fichier Texte que je peux manipuler à ma guise
Set Rst = New ADODB.Recordset
With Rst
.CursorLocation = adUseClient
.CursorType = adOpenDynamic
.LockType = adLockPessimistic
.Open cmdadodb
End With
NB : Le dossier indiqué par DBQ doit contenir un fichier du nom de "schema.ini" qui a la structure de ton fichier texte.
Pour mieux voir ça regarde ma source http://www.vbfrance.com/code.aspx?ID=33090
cs_Didier72
Messages postés76Date d'inscriptiondimanche 10 octobre 2004StatutMembreDernière intervention13 juin 2015 18 août 2006 à 08:33
Hello
Si ela peut apporter un plus
Moi j'utilise cette procédure:
------------------------------------------------------------------
strAdresseFichier = cheminfichier + "fichier.txt"
If (Dir(strAdresseFichier, vbDirectory) <> "") Then
Open strAdresseFichier For Input As #1
While Not EOF(1)
z = z + 1
Line Input #1, strLigne
tabLigne = Split(strLigne, ";")
info1(z) = tabLigne(0)
info2(z) = tabLigne(1)
info3(z) = tabLigne(2)
info4(z) ..... etc Etc
Wend
Close #1
End If
gnieark
Messages postés53Date d'inscriptionjeudi 17 août 2006StatutMembreDernière intervention22 octobre 2010 17 août 2006 à 22:53
merci vos aides sont précieuses. je potasserai tout ça dès demain.
Une petite question: Y'a-t-il une technique pour que le tableau de variable ne se réinitialise pas lorsque le programme s'arrete le temps d'une intervention de l'utilisateur? ou lorsque le programme change de feuille?
merci d'avance!
jean_marc_n2
Messages postés170Date d'inscriptionjeudi 11 décembre 2003StatutMembreDernière intervention24 janvier 2009 17 août 2006 à 21:29
Hello,
Tant qu'à écrire une fonction, autant alors que ce soit "vraiment" une fonction, ce qui n'est pas le cas ici:
- Passer le délimiteur en paramètre
- Passer le tableau en paramètre (on le réallouera dynamiquement)
Note: Il y a une faute de frappe dans le code ci dessus. Il faut bien sur lire:
While NotEOF(iFile) et pas EOF(1)
bouv
Messages postés1411Date d'inscriptionmercredi 6 août 2003StatutMembreDernière intervention 3 mars 20191 17 août 2006 à 15:58
Autre petit conseil,
Utilise un séparateur plus rare que le ';' (par ex '|') ou carément un séparateur perso (ex : '<%S%>').
Car tu risque un jour de te trouver avec un champs qui contient un ';' et toutes tes valeurs seront décalés.
Ce qui donnerait :
DANS TON FICHIER
domaine<%S%>Référence<%S%>Type<%S%>...
Dans ton code :
Private Sub Import(sFileName As String)
Const sDelimiter = "|"
Dim iFile As Integer, i As Integer, iLine As Integer
Dim sLine As String, sTable() As String, sResult(1 To 1000, 1 To 50) As String
'On récupère un numéro de fichier libre
iFile = FreeFile()
'On ouvre le fichier
Open sFileName For Input As #iFile
'On parcour chaque ligne
Do While Not EOF(1)
'On incrémente le n° de ligne
iLine = iLine + 1
'On lit la ligne
Line Input #1, sLine
'On sépare les champs
sTable = Split(sLine, sDelimiter)
'On tri les champs et on les place dans le Tableau sResult
For i = 0 To UBound(sTable)
sResult(iLine, i + 1) = sTable(i)
Next i
Loop
'On ferme le fichier
Close #iFile
End Sub
gnieark
Messages postés53Date d'inscriptionjeudi 17 août 2006StatutMembreDernière intervention22 octobre 2010 17 août 2006 à 14:23
je vais suivre tes conseils Cacophrene, merci. préciser à chaque fois le type de variable.
en fait la disposition du fichier texte sera
domaine;Référence;Type;Titre;Emetteur;Version;Visualiser;Imprimer;Importer;Chemin;Destinataires;Int;Ext;Mots clefs;date de mise en application;date de revision
(avec certaines valeurs boolennes, d'autres chaines de caractères d'autres numériques.
Je préfère utiliser les retours à la ligne même si j'alourdis le code, parceque je n'ai pas toujours toutes les informations et il se peut que le nombre d'éléments varie par ligne. De plus en cas de soucis ce sera moins galère pour aller modifier direct dans le fichier .txt
petite précision, ce fichier sera placé dans un repertoire dont je suis le seul (avec mon chef) à avoir l'accès en écriture, les autres l'ont en lecture seulement, c'est pourquoi je ne m'embète pas à sécuriser.
je posterai la suite du code (notemment les fonctions de recherche par critère)
Cacophrene
Messages postés251Date d'inscriptionlundi 29 mars 2004StatutMembreDernière intervention 4 mars 20081 17 août 2006 à 09:44
Décidément ! :-( C'est pas non plus "End Function" mais "End Sub". Ah les étouderies... :-)
Cacophrene
Messages postés251Date d'inscriptionlundi 29 mars 2004StatutMembreDernière intervention 4 mars 20081 17 août 2006 à 09:42
Petite correction : dans ma fonction Import, il ne faut pas lire sFileName As Integer (...!) mais sFileName As String.
Merci d'avance,
Cacophrène
Cacophrene
Messages postés251Date d'inscriptionlundi 29 mars 2004StatutMembreDernière intervention 4 mars 20081 17 août 2006 à 09:41
Salut !
Remplace :
Dim ligne, x As Integer
Dim filename, prout As String
Par :
Dim ligne As Integer (ou As Long si tu veux), x As Integer
Dim filename As String, prout As String
Si le type n'est pas précisé pour chaque variable, toutes celles où celui-ci n'apparaît pas sont considérées par VB comme Variant.
Sinon, tu peux (mais ce n'est pas aussi important que les types... surtout si tu es sûr de n'ouvrir qu'un seul fichier à la fois) utiliser FreeFile au lieu d'un chiffre en dur.
Dernière chose à dire : le découpage en lignes t'est-il utile ? Si c'est le cas, ne tiens pas compte de la suite de mon message. Si, au contraire, les lignes ne sont pas très importantes (c'est-à-dire si tu peux remplacer vbCrLf par un délimiteur), tu peux t'en tirer à moindre coût :
'=========================================================
Private Sub Import(sFileName As Integer)
Dim sData As String, F As Integer, sResult() As String
F = FreeFile()
Open sFileName For Input As #F
sData = Input$(LOF(F), #F)
Close #F
sResult = Split(sData, ";")
End Function
'=========================================================
Voilà tout ! Encore désolé si la fin du message est sans rapport avec ce que tu souhaites faire à partir de la disposition des données dans le fichier texte.
20 août 2006 à 09:54
Au retour de la fonction, il suffit de faire:
Dim r As Boolean, szErr As String
Dim t() As String
Dim nb_lignes as long, nb_champs as long
r = ImportTxtFile("c:\test.dat", ";", t(), szErr, 1)
' RECUP NOMBRE LIGNES
nb_lignes = Ubound(t(), 1)
Tu peux aussi récupérer le nombre de champs:
nb_champs = Ubound(t(), 2)
20 août 2006 à 00:25
19 août 2006 à 23:58
pour la suite je vais tenter d'intégrer à ta fonction une variable contenant le nombre de lignes du texte.
Si j'y arrive pas j'appellerai à l'aide ;)
19 août 2006 à 10:50
gnieark => Pour préserver ton tableau, il suffit que celui ci soit déclaré ailleurs que dans ta fonction.
VOici un exemple d'amélioration pour ta Sub:
- C'est maintenant une fonction qui retourne un booléen (True si tout va bien, False en cas d'erreur)
- Elle prend en paramètre le nom de fichier, le séparateur à utiliser, le tableau (qui sera alooué dynamiquement), une variable pour mettre le code d'erreur au cas ou (fichier non trouvé par exemple), et en option une variable permettant de commencer à remplir ton tableau à l'indice voulu (en général 0 ou 1).
Private Function ImportTxtFile(ByVal fileName As String, _
ByVal separator As String, _
ByRef tData() As String, _
ByRef errorString As String, _
Optional ByVal baseArray As Integer = 1) As Boolean
Dim f As Integer
Dim tLine() As String
Dim tSplit() As String
Dim buffer As String
Dim nbItem As Long
Dim i As Long, j As Long
On Error GoTo ImportTxtFile_ERR
f = FreeFile()
Open fileName For Binary As #f
buffer = Space$(LOF(f))
Get #f, , buffer
Close #f
tSplit() = Split(buffer, vbCrLf)
nbItem = UBound(Split(tSplit(0), separator)) + baseArray
ReDim tData(UBound(tSplit()) + baseArray, nbItem)
For i = LBound(tSplit()) To UBound(tSplit())
tLine = Split(tSplit(i), separator)
For j = LBound(tLine) To UBound(tLine)
tData(i + baseArray, j + baseArray) = tLine(j)
Next j
Next i
ImportTxtFile = True
ImportTxtFile_END:
Exit Function
ImportTxtFile_ERR:
errorString = Err.Description
Resume ImportTxtFile_END
End Function
Un exemple d'appel:
Private Sub Command2_Click()
Dim r As Boolean, szErr As String
Dim t() As String
r = ImportTxtFile("c:\test.dat", ";", t(), szErr, 1)
End Sub
Avantages:
- Tout est passé en paramètres, plus rien de hard-codé dans la "Sub"
- L'allocation du tableau est dynamique, aussi bien pour les lignes que pour les colonnes: tu peux lire n'importe quel fichier, de n'importe quelle taille, le code est toujours valable
- La lecture en bloc est très rapide
- C'est une vraie fonction, utilisable de façon autonome.
Au final, ça charge un fichier de 20000 lignes avec 7 champs par lignes en 0,4 seconde.
Bonne suite :-)
18 août 2006 à 11:49
Au fait vu ton niveau très appréciable pourras-tu me faire des remarques et suggestions pour son amélioration?
18 août 2006 à 11:26
Dommage que ta source ne contienne pas de vrai zip avec un projet exemple.
18 août 2006 à 11:02
Dim Cnx As ADODB.Connection
Dim cmdadodb As ADODB.Command, sCommandText as string
Dim Rst as ADODB.Recordset
'Definition et ouverture de la Connexion
StrCnx = "driver={Microsoft Text Driver (*.txt; *.csv)};DriverId=27" & _
";DBQ=" & App.Path & "\DATA\ASCII" 'DBQ désigne le dossier où se trouve le fichier ASCII
Set Cnx = New ADODB.Connection
With Cnx
.ConnectionString = StrCnx
.Open
End With
'Définition de la commande, elle peut être une requête sur ton fichier Texte.
sCommandText = "[Mon fichier ascii.txt]" 'Ne pas oublier les crochets.
Set cmdadodb = New ADODB.Command
With cmdadodb
.ActiveConnection = Cnx
.CommandType = adCmdUnknown
.CommandText = sCommandText
End With
'Ma variable recordset Rst contiendra tout le fichier Texte que je peux manipuler à ma guise
Set Rst = New ADODB.Recordset
With Rst
.CursorLocation = adUseClient
.CursorType = adOpenDynamic
.LockType = adLockPessimistic
.Open cmdadodb
End With
NB : Le dossier indiqué par DBQ doit contenir un fichier du nom de "schema.ini" qui a la structure de ton fichier texte.
Pour mieux voir ça regarde ma source http://www.vbfrance.com/code.aspx?ID=33090
18 août 2006 à 08:33
Si ela peut apporter un plus
Moi j'utilise cette procédure:
------------------------------------------------------------------
strAdresseFichier = cheminfichier + "fichier.txt"
If (Dir(strAdresseFichier, vbDirectory) <> "") Then
Open strAdresseFichier For Input As #1
While Not EOF(1)
z = z + 1
Line Input #1, strLigne
tabLigne = Split(strLigne, ";")
info1(z) = tabLigne(0)
info2(z) = tabLigne(1)
info3(z) = tabLigne(2)
info4(z) ..... etc Etc
Wend
Close #1
End If
-----------------------------------------------------------------
bye
17 août 2006 à 22:53
Une petite question: Y'a-t-il une technique pour que le tableau de variable ne se réinitialise pas lorsque le programme s'arrete le temps d'une intervention de l'utilisateur? ou lorsque le programme change de feuille?
merci d'avance!
17 août 2006 à 21:29
Tant qu'à écrire une fonction, autant alors que ce soit "vraiment" une fonction, ce qui n'est pas le cas ici:
- Passer le délimiteur en paramètre
- Passer le tableau en paramètre (on le réallouera dynamiquement)
Note: Il y a une faute de frappe dans le code ci dessus. Il faut bien sur lire:
While NotEOF(iFile) et pas EOF(1)
17 août 2006 à 15:58
Utilise un séparateur plus rare que le ';' (par ex '|') ou carément un séparateur perso (ex : '<%S%>').
Car tu risque un jour de te trouver avec un champs qui contient un ';' et toutes tes valeurs seront décalés.
Ce qui donnerait :
DANS TON FICHIER
domaine<%S%>Référence<%S%>Type<%S%>...
Dans ton code :
Private Sub Import(sFileName As String)
Const sDelimiter = "|"
Dim iFile As Integer, i As Integer, iLine As Integer
Dim sLine As String, sTable() As String, sResult(1 To 1000, 1 To 50) As String
'On récupère un numéro de fichier libre
iFile = FreeFile()
'On ouvre le fichier
Open sFileName For Input As #iFile
'On parcour chaque ligne
Do While Not EOF(1)
'On incrémente le n° de ligne
iLine = iLine + 1
'On lit la ligne
Line Input #1, sLine
'On sépare les champs
sTable = Split(sLine, sDelimiter)
'On tri les champs et on les place dans le Tableau sResult
For i = 0 To UBound(sTable)
sResult(iLine, i + 1) = sTable(i)
Next i
Loop
'On ferme le fichier
Close #iFile
End Sub
17 août 2006 à 14:23
en fait la disposition du fichier texte sera
domaine;Référence;Type;Titre;Emetteur;Version;Visualiser;Imprimer;Importer;Chemin;Destinataires;Int;Ext;Mots clefs;date de mise en application;date de revision
(avec certaines valeurs boolennes, d'autres chaines de caractères d'autres numériques.
Je préfère utiliser les retours à la ligne même si j'alourdis le code, parceque je n'ai pas toujours toutes les informations et il se peut que le nombre d'éléments varie par ligne. De plus en cas de soucis ce sera moins galère pour aller modifier direct dans le fichier .txt
petite précision, ce fichier sera placé dans un repertoire dont je suis le seul (avec mon chef) à avoir l'accès en écriture, les autres l'ont en lecture seulement, c'est pourquoi je ne m'embète pas à sécuriser.
je posterai la suite du code (notemment les fonctions de recherche par critère)
17 août 2006 à 09:44
17 août 2006 à 09:42
Merci d'avance,
Cacophrène
17 août 2006 à 09:41
Remplace :
Dim ligne, x As Integer
Dim filename, prout As String
Par :
Dim ligne As Integer (ou As Long si tu veux), x As Integer
Dim filename As String, prout As String
Si le type n'est pas précisé pour chaque variable, toutes celles où celui-ci n'apparaît pas sont considérées par VB comme Variant.
Sinon, tu peux (mais ce n'est pas aussi important que les types... surtout si tu es sûr de n'ouvrir qu'un seul fichier à la fois) utiliser FreeFile au lieu d'un chiffre en dur.
Dernière chose à dire : le découpage en lignes t'est-il utile ? Si c'est le cas, ne tiens pas compte de la suite de mon message. Si, au contraire, les lignes ne sont pas très importantes (c'est-à-dire si tu peux remplacer vbCrLf par un délimiteur), tu peux t'en tirer à moindre coût :
'=========================================================
Private Sub Import(sFileName As Integer)
Dim sData As String, F As Integer, sResult() As String
F = FreeFile()
Open sFileName For Input As #F
sData = Input$(LOF(F), #F)
Close #F
sResult = Split(sData, ";")
End Function
'=========================================================
Voilà tout ! Encore désolé si la fin du message est sans rapport avec ce que tu souhaites faire à partir de la disposition des données dans le fichier texte.
Cordialement,
Cacophrène