Modifier taille d'un fichier ouvert en binary

inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012 - 28 juil. 2012 à 12:32
inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012 - 28 juil. 2012 à 23:12
Bonjour,

J'ai un problèmes de taille de fichier en VBA avec l'instruction open en mode binary
Je souhaite supprimer ou modifier des données dans un fichier.
Cependant malgré les solutions proposées sur ce forum, ça ne marche pas.

Voici en sytnhétique mon code :
'J'ouvre le fichier en lecture
Open nom_fichier For Binary Access Read Lock Read As #1
'J'ouvre mon fichier en mode écriture
Open nom_fichier For Binary Access Write Lock Write As #2
'Je lit les données dans le fichier
get #1,,entete
get #1,,données1
get #1,,données2
get #1,,données3
'Je ferme la première instance d'open
close #1
'Je met les données dans le fichier
put #2,,entete
put #2,,données1
put #2,,données3 'remarquez que je met pas les données2 dans le fichier
'Je ferme la deuxième instance d'open
close #2

=> ce qu'il se passe : le fichier n'est pas raccourcit : c'est comme si j'avais dans le fichier
entete
données1
données3
données3
=> en fait le dernier "données3" est resté dans le fichier "à sa place".

PS : vous aurez remarquer le mot lock dans l'instruction open : le fichier étant suceptible d'être utilisé par un autre process => DONC pas question de supprimer le fichier (un autre process pourrait alors rajouter des données le temps de supprimer...)

Est-ce quelqu'un sait pourquoi le fichier #2 ne se termine pas après l'ajout des données ? Existe-t-il une instruction pour définir la fin du fichier, supprimer la fin ?
Merci pour votre aide

11 réponses

ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 juil. 2012 à 13:06
Bonjour,
Lorsque tu ouvres un fichier, il est ouvert et nul autre instance de ce fichier ne pourrait contrecarrer cette ouverture. Il en irait différemment si tu mettait en mémoire les données à l'ouverture, fermais le fichier, puis réécrivais les données dans le fichier ouvert à nouveau.
Autre manière de procéder : ouvrir le fichier, en créer un autre et l'ouvrir, écrire dans le second puis écraser le premier par le second.

Avant d'aller plus loin, toutefois, il nous faut savoir avec précision :
- comment a été écrit (sa structure exacte) le fichier que tu ouvres et veux modifier.


________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012
28 juil. 2012 à 15:08
Merci pour cettre réponse,
cependant j'ai essayé d'intervertir les deux ouvertures de fichier :
1-ouvrir d'abord en écriture (#2)
2-réouvrir en lecture (#1)
3-lire le fichier et le fermer (#1)
4-mettre les données dans le fichier (#2)
mais j'ai le même résultat.
Faut-il absolument supprimer le fichier pour en réduire la longeur ?

Passer par un fichier tampon ne marche pas car le temps de d'écraser le premier fichier, il se peut qu'un autre process l'ai récréer.

PS : pour expliquer un peu plus la raison de ce code, je dois faire une sorte de base de données (plan d'actions) avec un fichier sur le réseau ou plusieurs utilisateur peuvent accéder, ajouter, supprimer des données. Pour répondre à ta question sur la structure du fichier elle est de la sorte
1-Nombre de données (string*12)
2-Type de donnée qui va suivre (string*3)
3-Longeur de la donnée qui va suivre (string*12)
4-La données en elle même (un Type défini par moi même avec différent type de variable (d'où le mode binary))
5-on reboucle à 2
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 juil. 2012 à 15:37
Attends un peu, là ...
Tu as donc pour ce faire normalement déclaré une structure (un type).
1) On ne la voit pas : montre-la
2) elle est à utiliser tant en écriture qu'en lecture. on ne voit pas cette utilisation
3) il te faut alors ouvrir For Random.

Un fichier ainsi ouvert, tant en lecture qu'en écriture, ne peut l'être avant sa fermeture, ce qui fait que ton problème de protection n'existe plus !

________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012
28 juil. 2012 à 16:05
Mon problème n'est pas celui du blocage du fichier : Lock le fait très bien (il bloque même le bloc note par exemple, ce que ne fait pas random)
Random oblige aussi à faire un autre fichier tampon et écraser l'ancien fichier. Donc ce n'est pas la solution.

Voici mon code complet :
Public Const PA_Version_Plan_d_action = "001"       ' Version actuelle du plan d'action
Public Const PA_Fichier_Plan_d_action = "c:\PA.txt" ' Chemin du plan d'action (Variable à l'avenir ?)

Public Type Action
    'Les champs commençant par z donne la taille du champ suivant (sauf si taille figées)
    Numéro_action As String * 12               'Numéro unique de l'action
    Numéro_depp As String
    Problème As String
    Cause As String
    Action_à_faire As String
    Responsable_action As String            'login du pilote
    Délai As String
    Durée As String                         'Durée prévue de l'action
    Délai_replanifié As String
    Daté_réalisation As String
    Avancement As String                    'Pourcentage : de 0 à 100
    Commentaire As String
    Créateur As String                      'Nom de celui qui a créér l'action
    Date_création As String                 'Date de la création de l'action
    Efficacité As String
    Vérif_faite_par As String
    Vérif_faite_le As String
    Vérif_Commentaire As String
    Catégorie1 As String
    Catégorie2 As String
    Catégorie3 As String
    Catégorie4 As String
End Type

Public Function Ouvrir_Fichier_lecture(nom_fichier, numéro)
On Error Resume Next
boucle = 0
Do
    Open nom_fichier For Binary Access Read Lock Read As numéro
    If Err.Number = 0 Then Exit Do  'Pas d'erreur : on quitte
    desc = Err.Description
    Err.Clear                       'On efface l'erreur précédente
    boucle = boucle + 1
    If boucle = 5 Then Exit Do      '5 tentatives : on quitte avec une erreur
    t = Now + TimeValue("00:00:02") 'Sinon on attend 2 secondes et on réessaye
    Do While t > Now: Loop
Loop

If boucle = 5 Then
    Charger_Fichier = desc 'On retourne la description de l'erreur
Else
    Charger_Fichier = ""
End If
End Function

Public Function Ouvrir_Fichier_ecriture(nom_fichier, numéro)
On Error Resume Next
boucle = 0
Do
    Open nom_fichier For Binary Access Write Lock Write As numéro
    If Err.Number = 0 Then Exit Do  'Pas d'erreur : on quitte
    desc = Err.Description
    Err.Clear                       'On efface l'erreur précédente
    boucle = boucle + 1
    If boucle = 5 Then Exit Do      '5 tentatives : on quitte avec une erreur
    t = Now + TimeValue("00:00:02") 'Sinon on attend 2 secondes et on réessaye
    Do While t > Now: Loop
Loop

If boucle = 5 Then
    Charger_Fichier = desc 'On retourne la description de l'erreur
Else
    Charger_Fichier = ""
End If
End Function

Public Function PA_Supprimer_action(num_action)
Dim longeur As String * 12
'On ouvre le fichier
                            'On ouvre le fichier 2
                                erreur2 = Ouvrir_Fichier_ecriture(PA_Fichier_Plan_d_action, 2)
    erreur = Ouvrir_Fichier_lecture(PA_Fichier_Plan_d_action, 1)
        'Si on a une erreur
            If erreur <> "" Or erreur2 <> "" Then
                'On a une erreur
                PA_Supprimer_action = erreur
                Exit Function
            End If
            
        ' On lit le fichier en entier
            tampon$ = String$(LOF(1), " ")
            Get #1, , tampon$
            append
        ' On cherche l'action concernée
            ' On retrouve le numéro de la dernière action ajoutée
                octet = 13
            'On boucle jusquà trouver le numéro
                trouvé = False
                Do
                    pos_ini = octet
                    'On passe la version de l'action
                        octet = octet + Len(PA_Version_Plan_d_action)
                    'On lit la longeur de l'action
                        lgr val(Mid(tampon$, octet, Len(longeur))): octet octet + Len(longeur)
                    'On lit le numéro de l'action
                        num = val(Mid(tampon$, octet, 12))
                        If num = num_action Then
                            'On tient notre action
                            'On copie le début
                                début$ = String$(pos_ini - 1, " ")
                                Get #1, 1, début$
                            'On copie la fin
                                fin$ = String$(LOF(1) - (pos_ini + 3 + 12 + lgr), " ")
                                Get #1, pos_ini + 3 + 12 + lgr, fin$
                            'On ferme le fichier 1
                                Close #1
                            'On colle le début
                                Put #2, 1, début$
                            'On colle la fin
                                Put #2, , fin$
                                MsgBox fin$
                                s = Seek(2)
                                Put #2, , "STOP!!!!!!!!!!!!"
                            trouvé = True
                            Exit Do
                        End If
                    'On lit l'action
                        octet = octet + lgr
                Loop While octet <= Len(tampon)
    Close #2
    Close #1

'On retourne un message si erreur
    If trouvé = False Then
        PA_Supprimer_action = "L'action n'a pas été trouvée"
    Else
        PA_Supprimer_action = ""
    End If
End Function
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012
28 juil. 2012 à 16:12
le "STOP !!!!!" c'était pour voir si les données étaient bien les données restantes de l'"ancien" fichier.

NB : pour ajouter une action :
Public Function PA_Ajouter_action(a As Action)
' Retourne false si pb, sinon retourne le numéro de l'action
Dim num_action As String * 12
Dim longeur As String * 12

   
'On ajoute l'action
    'Routine erreur d'ouverture + vérif fichier présent
    erreur = Ouvrir_Fichier(PA_Fichier_Plan_d_action, 1)
        'Si on a une erreur
            If erreur <> "" Then
                'On a une erreur
                PA_Ajouter_action = erreur
                Exit Function
            End If
        ' On retrouve le numéro de la dernière action ajoutée
            Get #1, 1, num_action
        ' et on l'incrémente
            c = val(num_action) + 1
            num_action = Str$(c)
            a.Numéro_action = num_action
            Put #1, 1, num_action
        ' On met la version de l'action
            Put #1, LOF(1) + 1, PA_Version_Plan_d_action
        'On met la longeur de l'action
            longeur = Str$(LenB(a))
            Put #1, , longeur
            posini = Seek(1)
        ' On met l'action
            Put #1, , a
            pos = Seek(1)
            longeur = pos - posini
            Put #1, posini - Len(longeur), longeur
    Close #1

' Tout c'est bien passé, on retourne le numéro de l'action
    PA_Ajouter_action = num_action

End Function
0
inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012
28 juil. 2012 à 17:15
Bon sinon j'ai bien une solution, dans la macro pour modifier le fichier
1-j'ouvre le fichier (#1) avec lock, pour être sûr que personne d'autre n'est dessus
2-je créé un fichier pipeau, genre "toto.txt" (#3)
3-je ferme le fichier (#1)
3-je copie les donnes dans un nouveau fichier temporaire (#2)
4-j'écrase le premier fichier (#1) par le temporaire (#2)
5-je supprime le fichier pipeau (#3)

Et pour lire ou écrire dans le fichier, je vérifie avant que le fichier pipeau (#3) n'existe pas.
S'il existe c'est que je suis en train de modifier le fichier (#1) : donc on attend un peu...

voilà, du coup le fichier temporaire (#2) sera de la bonne taille car créé de toute pièce.

Bon c'est pas du codage très propre, mais ça devrait marcher.
0
Utilisateur anonyme
28 juil. 2012 à 17:50
Bonjour,

Cela fait longtemps que je n'ai pas joué avec cela, mais il me semble que quand tu effaces quelque chose dans un fichier binaire, il faut que tu aies la place exacte de l'effacement, (il me semble que c'est avec Seek() et le nombre total d'octets effacés. Ensuite, pour réécrire au même endroit, il faut te repositionner au même endroit (peut-être avec seek()) et ne pas écrire plus d'octets qu'il y a d'octets effacés. À la moindre horreur (comme disait Sol), c'est la catapostrophe (toujours comme disait Sol).
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 juil. 2012 à 18:39
Le problème de l'ouverture en mode Binary est connu. Contrairement au comportement en mode Random, l'instruction Put (en mode binary) ajoute systématiquement à la fin . On ne peut faire autrement dans ce cas.
Voilà d'ailleurs ce qu'en dit l'aide VB6 :
For files opened in Binary mode, all of the Random rules apply, except:

· The Len clause in the Open statement has no effect. Put writes all variables to disk contiguously; that is, with no padding between records.
· For any array other than an array in a user-defined type, Put writes only the data. No descriptor is written.
· Put writes variable-length strings that are not elements of user-defined types without the 2-byte length descriptor. The number of bytes written equals the number of characters in the string.




________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
28 juil. 2012 à 19:23
Après mon pastis :
Voilà ce que je ferais à ta place :
- ouverture une seule fois en mode random (permet d'écrire et de modifier)
- modifier par "" ou 0 selon le type dans la structure les enregistr'ements à ne pas garder
- fermeture

De temps à autre et hors plage de travail : nettoyage du fichier ainsi :
- ouverture en random ===>> lire et alimenter un tableau de structure à utiliser ensuite pour créer un nouveau fichier, en ne gardant que ce qui n'est pas "rejeté" ( "", 0 ...)
- ou (pareil) : ouvrir le fichier + 1 autre bis en random et n'alimenter le bis que de ce qui n'a pas été rejeté ("", 0, ...)
Dans un cas comme dans l'autre : ecraser l'original par le bis
Si tu ne veux pas de "trous" ===>> méthode su sapeur Camembert : pour chaque enregistrement à rejeter : tu lui substitues le dernier non "vide", puis "vide" le dernier non vide ________________________
Réponse exacte ? => "REPONSE ACCEPTEE" pour faciliter les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement vous dire ce qu'elle contient. Je n'interviendrai qu'en cas de nécessité de développ
0
inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012
28 juil. 2012 à 23:07
bon, dans l'ordre:
-cmarcotte :
--Oui seek parmet de faire ça (je l'utilise par ailleurs)
--Non on peut mettre plus de données que celles remplacées mais il ne faut pas oublier de déplacer ce qu'il y avait après. Agrandir un fichier n'est pas un soucis.
--Pour remettre des données à un endroit précis il suffit de définir "pos" dans l'instruction put #1,pos,données.

-ucfoutu:
--Il doit y avoir un pb de traduction (désolé) car ce que dit l'aide c'est, que les données sont mises bout à bout (contrairement à random), que "len" ne sert à rien : la longeur de ce que tu lis correspond au type de variable mis en argument dans l'instruction get. Le deuxième point parle des tableaux, rien à voir avec notre sujet.
--
l'instruction Put (en mode binary) ajoute systématiquement à la fin
: non, idem, il suffit de définir "pos" dans l'instruction put #1,pos,données.
--Merci sinon pour ton idée de remplacer par des "" ou 0. L'intérêt serait alors de gagner du temps à l'enregistrement des données, mais il faut avoir un pc qui hors du temps de travail épure le fichier...+ contraignant déjà.

Au final, j'opte pour le fichier temporaire. Je vous envoie le code dès que c'est fini.
0
inteloide2 Messages postés 16 Date d'inscription jeudi 30 décembre 2010 Statut Membre Dernière intervention 1 septembre 2012
28 juil. 2012 à 23:12
Et voilà
j'ai testé, ça marche

Public Const PA_Version_Plan_d_action = "001"       ' Version actuelle du plan d'action
Public Const PA_Fichier_Plan_d_action = "c:\PA.txt" ' Chemin du plan d'action (Variable à l'avenir ?)

Public Type Action
    'Les champs commençant par z donne la taille du champ suivant (sauf si taille figées)
    Numéro_action As String * 12               'Numéro unique de l'action
    Numéro_depp As String
    Problème As String
    Cause As String
    Action_à_faire As String
    Responsable_action As String            'login du pilote
    Délai As String
    Durée As String                         'Durée prévue de l'action
    Délai_replanifié As String
    Daté_réalisation As String
    Avancement As String                    'Pourcentage : de 0 à 100
    Commentaire As String
    Créateur As String                      'Nom de celui qui a créér l'action
    Date_création As String                 'Date de la création de l'action
    Efficacité As String
    Vérif_faite_par As String
    Vérif_faite_le As String
    Vérif_Commentaire As String
    Catégorie1 As String
    Catégorie2 As String
    Catégorie3 As String
    Catégorie4 As String
End Type

Public Function Ouvrir_Fichier_lecture(nom_fichier, numéro)
On Error Resume Next
boucle = 0
Do
    If Dir(nom_fichier & "bloquer") <> "" Then
        'Le fichier est bloqué pour l'instant, on boucle
    Else
        Open nom_fichier For Binary Access Read Lock Read As numéro
        If Err.Number = 0 Then Exit Do  'Pas d'erreur : on quitte
        desc = Err.Description
        Err.Clear                       'On efface l'erreur précédente
    End If
    
    boucle = boucle + 1
    If boucle = 5 Then Exit Do      '5 tentatives : on quitte avec une erreur
    t = Now + TimeValue("00:00:02") 'Sinon on attend 2 secondes et on réessaye
    Do While t > Now: Loop
Loop

If boucle = 5 Then
    Charger_Fichier = desc 'On retourne la description de l'erreur
Else
    Charger_Fichier = ""
End If
End Function

Public Function Ouvrir_Fichier_ecriture(nom_fichier, numéro)
On Error Resume Next
boucle = 0
Do
    If Dir(nom_fichier & "bloquer") <> "" Then
        'Le fichier est bloqué pour l'instant, on boucle
    Else
        Open nom_fichier For Binary Access Write Lock Write As numéro
        If Err.Number = 0 Then Exit Do  'Pas d'erreur : on quitte
        desc = Err.Description
        Err.Clear                       'On efface l'erreur précédente
    End If
    
    boucle = boucle + 1
    If boucle = 5 Then Exit Do      '5 tentatives : on quitte avec une erreur
    t = Now + TimeValue("00:00:02") 'Sinon on attend 2 secondes et on réessaye
    Do While t > Now: Loop
Loop

If boucle = 5 Then
    Charger_Fichier = desc 'On retourne la description de l'erreur
Else
    Charger_Fichier = ""
End If
End Function

Public Function Bloquer_Fichier_ecriture(nom_fichier, numéro)
Open nom_fichier & "bloquer" For Output As numéro
    Print #numéro, "bloquer"
Close numéro
End Function

Public Function Débloquer_Fichier_ecriture(nom_fichier)
Kill (nom_fichier & "bloquer")
End Function

Public Function PA_Ajouter_action(a As Action)
' Retourne false si pb, sinon retourne le numéro de l'action
Dim num_action As String * 12
Dim longeur As String * 12

   
'On ajoute l'action
    'Routine erreur d'ouverture + vérif fichier présent
    erreur = Ouvrir_Fichier(PA_Fichier_Plan_d_action, 1)
        'Si on a une erreur
            If erreur <> "" Then
                'On a une erreur
                PA_Ajouter_action = erreur
                Exit Function
            End If
        ' On retrouve le numéro de la dernière action ajoutée
            Get #1, 1, num_action
        ' et on l'incrémente
            c = val(num_action) + 1
            num_action = Str$(c)
            a.Numéro_action = num_action
            Put #1, 1, num_action
        ' On met la version de l'action
            Put #1, LOF(1) + 1, PA_Version_Plan_d_action
        'On met la longeur de l'action
            longeur = Str$(LenB(a))
            Put #1, , longeur
            posini = Seek(1)
        ' On met l'action
            Put #1, , a
            pos = Seek(1)
            longeur = pos - posini
            Put #1, posini - Len(longeur), longeur
    Close #1

' Tout c'est bien passé, on retourne le numéro de l'action
    PA_Ajouter_action = num_action

End Function

Public Function PA_Supprimer_action(num_action)
Dim longeur As String * 12
'On ouvre le fichier
    erreur = Ouvrir_Fichier_lecture(PA_Fichier_Plan_d_action, 1)
        'Si on a une erreur
            If erreur <> "" Then
                'On a une erreur
                Close #1
                PA_Supprimer_action = erreur
                Exit Function
            End If
            
'On bloque le fichier
    erreur = Bloquer_Fichier_ecriture(PA_Fichier_Plan_d_action, 3)
    
        'Si on a une erreur
            If erreur <> "" Then
                'On a une erreur
                Close #1
                PA_Supprimer_action = erreur
                Exit Function
            End If
            
        ' On lit le fichier en entier
            tampon$ = String$(LOF(1), " ")
            Get #1, , tampon$
            
        ' On cherche l'action concernée
            ' On retrouve le numéro de la dernière action ajoutée
                octet = 13
            'On boucle jusquà trouver le numéro
                trouvé = False
                Do
                    pos_ini = octet
                    'On passe la version de l'action
                        octet = octet + Len(PA_Version_Plan_d_action)
                    'On lit la longeur de l'action
                        lgr val(Mid(tampon$, octet, Len(longeur))): octet octet + Len(longeur)
                    'On lit le numéro de l'action
                        num = val(Mid(tampon$, octet, 12))
                        If num = num_action Then
                            'On tient notre action
                            'On copie le début
                                début$ = String$(pos_ini - 1, " ")
                                Get #1, 1, début$
                            'On copie la fin
                                fin$ = String$(LOF(1) - (pos_ini + 3 + 12 + lgr), " ")
                                Get #1, pos_ini + 3 + 12 + lgr, fin$
                            'On ferme le fichier 1
                                Close #1
                            'On ouvre le fichier 2
                                erreur2 = Ouvrir_Fichier_ecriture(PA_Fichier_Plan_d_action & "tmp", 2)
                                If erreur2 <> "" Then sdf = 1
                            'On colle le début"""
                                Put #2, 1, début$
                            'On colle la fin
                                Put #2, , fin$
                            trouvé = True
                            Exit Do
                        End If
                    'On lit l'action
                        octet = octet + lgr
                Loop While octet <= Len(tampon)
    Close #2
    Close #1
    Kill PA_Fichier_Plan_d_action                                       ' on supprime le fichier du plan d'action
    Name PA_Fichier_Plan_d_action & "tmp" As PA_Fichier_Plan_d_action   ' on renomme le fichier temporaire
    Débloquer_Fichier_ecriture (PA_Fichier_Plan_d_action)               ' et on le débloque

'On retourne un message si erreur
    If trouvé = False Then
        PA_Supprimer_action = "L'action n'a pas été trouvée"
    Else
        PA_Supprimer_action = ""
    End If
End Function
0
Rejoignez-nous