none
MyBitConverter.GetBytes en procédure plutôt qu'en fonction RRS feed

  • Question

  • Bonjour

    exposé du problème dans une boucle de grande dimension dans laquelle des échanges se font entre variables résultant de la boucle est leur inscription dans un stream il faut passer par un tableau de byte.

    le fait d'utiliser la fonction BitConverter.GetBytes(...) retourne la construction d'un nouveau tableau pour la même variable prise en boucle. si cette fonction était une procédure avec un paramètre de retour de type tableau de byte, il n'y aurait aucune construction de tableau puisque ce serait le même qui serait utilisé en fonction de cette même variable.

    Exemple :

    dim f as filestream = un fichier ok en position

    for esch valeur as long in trèsgrandelistedelong

    f.write(bitconverter.getbytes(valeur,0,len(valeur))

    next

    à chaque passage dans la boucle un nouveau tableau est construit inutilement

    exemple 2 en supposant un

    sub MyBitConverter.GetBytes (byval value as type, byref untableaudéfinit() as byte, byval optional offsetdépart as integer = 0)

    ...

    end sub

    ainsi dans MyBitConverter.GetBytes  le résultat est directement transmit à " untableaudéfinit " sans avoir besoin de construire un nouveau tableau et ainsi conserver une pile basse consomation ;-) et une rapidité plus accru

    alors je me suis penché un peu sur la question en utilisant les opérateurs de bits mais j'ai un souci! :-(

    pour un type long  le fait de décaler vers la gauche de 64bits permet d'avoir que des zéros enfin c'est ce que j'ai toujours vu hors en visual basic ce même décalage fournit le même résultat qu'au départ et la je pers un peu les pédales. Alors s'il y a quelqu'un pour moi GROS BISOU  ;-)

    Merci,

     

     

    mercredi 1 septembre 2010 14:16

Réponses

  • Ok, même si je vois mal l'avantage de la solution des décalages. Cela pourrait donner :

       Dim fs As IO.FileStream
        Dim Data(1) As Long
        Data(0) = &H4142434445464748
        Data(1) = &H4847464544434241
    
        ' Méthode 1
        fs = New IO.FileStream("c:\a.txt", IO.FileMode.Create)
        Dim bw As New IO.BinaryWriter(fs)
        For Each Value As Long In Data
          bw.Write(Value)
        Next
        bw.Close()
    
        ' Méthode 2
        fs = New IO.FileStream("c:\b.txt", IO.FileMode.Create)
        Dim b(7) As Byte
        Dim shift As Integer
        For Each value As Long In Data
          shift = 0
          For i = 0 To 7
            b(i) = (value >> shift) And &HFF
            shift += 8
          Next
          fs.Write(b, 0, 8)
        Next
        fs.Close()
    

    Dans du code normal, ne pas écrite à la racine du disque (un utilisateur non admin n'y a pas les droits).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    • Marqué comme réponse CentSoucis jeudi 2 septembre 2010 09:40
    jeudi 2 septembre 2010 09:04
    Modérateur
  • Bonjour, j'ai fini par trouver une solution temporaire ne fonctionnant qu'avec les nombres positifs je vous fais part de la procédure en utilisant un ULong au lieu d'un Long:

    Public

     

    Class Form1

     

    Private tamponLong(Len(0L) - 1) As Byte

     

    Private Sub MyBitConverter_GetBits(ByVal valeur As ULong, ByRef tampon() As Byte, ByVal offset As Integer)

    tampon(0) = (valeur << 7 * 8) >> 7 * 8

    tampon(1) = (valeur << 6 * 8) >> 6 * 8 + 1 * 8

    tampon(2) = (valeur << 5 * 8) >> 5 * 8 + 2 * 8

    tampon(3) = (valeur << 4 * 8) >> 4 * 8 + 3 * 8

    tampon(4) = (valeur << 3 * 8) >> 3 * 8 + 4 * 8

    tampon(5) = (valeur << 2 * 8) >> 2 * 8 + 5 * 8

    tampon(6) = (valeur << 1 * 8) >> 1 * 8 + 6 * 8

    tampon(7) = (valeur << 0 * 8) >> 0 * 8 + 7 * 8

     

    End Sub

     

    Private Sub Form1_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown

     

    Dim val As ULong = Long.MaxValue

    MyBitConverter_GetBits(val, tamponLong, 0)

     

    End Sub

    End

     

    Class

    Merci

    • Marqué comme réponse CentSoucis jeudi 2 septembre 2010 08:26
    jeudi 2 septembre 2010 08:24
  • Bonjour Monsieur SCRIBE ainsi  qu'à tous,

    La méthode 2 me convient parfaitement et merci pour le And FF et oui bien sûr! Merci beaucoup.

    • Marqué comme réponse CentSoucis jeudi 2 septembre 2010 09:40
    jeudi 2 septembre 2010 09:40
  •  

    Private Sub MyBitConverter_GetBits(ByVal valeur As Long, ByRef tampon() As Byte, ByVal offset As Integer)

    tampon(offset + 0) = (valeur

    And &HFFL) >> 0 * 8

    tampon(offset + 1) = (valeur

    And &HFFFFL) >> 1 * 8

    tampon(offset + 2) = (valeur

    And &HFFFFFFL) >> 2 * 8

    tampon(offset + 3) = (valeur

    And &HFFFFFFFFL) >> 3 * 8

    tampon(offset + 4) = (valeur

    And &HFFFFFFFFFF) >> 4 * 8

    tampon(offset + 5) = (valeur

    And &HFFFFFFFFFFFF) >> 5 * 8

    tampon(offset + 6) = (valeur

    And &HFFFFFFFFFFFFFF) >> 6 * 8

     

    Try

    tampon(offset + 7) = (valeur

    And &HFFFFFFFFFFFFFFFF) >> 7 * 8

     

    Catch EX As OverflowException

    tampon(offset + 7) =

    Not valeur >> 7 * 8

    tampon(offset + 7) = tampon(offset + 7)

    Or &HFF

     

    End Try

     

    End Sub

    Voilà, grace à vous le problème est résolu.

    Je vous remercie beaucoup et à bientôt pour de nouvelle aventure

    • Marqué comme réponse CentSoucis vendredi 3 septembre 2010 06:49
    vendredi 3 septembre 2010 06:47
  • erreur dans le catch: correction

    Catch EX As OverflowException

    tampon(offset + 7) =

    Not valeur >> 7 * 8

    tampon(offset + 7) =

    Not tampon(offset + 7)

     

    End Try

    Mille fois merci

    • Marqué comme réponse CentSoucis vendredi 3 septembre 2010 07:47
    vendredi 3 septembre 2010 07:37

Toutes les réponses

  • Bonjour,

    Dans votre cas, utilisez l'objet BinaryWriter :

    Using br As BinaryWritrer = new BinaryWriter(fileStream)
     br.Write(valeur)
    End Using
    

    Cordialement


    Gilles TOURREAU - MVP C# - MCTS ADO .NET 3.5 - MCPD Windows Developper 3.5 - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    mercredi 1 septembre 2010 14:46
    Modérateur
  • Bonsoir Monsieur TOURREAU,

    ce n'est pas la bonne solution si l'on considère que le flux doit resté ouvert après fermeture de l'outil d'écriture ou de lecture comme binary...

    le constructeur de binary reçoi en paramère le flux auquel il est connecté, ce n'est donc pas à binary... de fermer le flux

    sinon binary... est très bien mais mon cas se situe comme je l'ai dit au départ et c'est de ce point de vue que j'ai besoin

    Merci,

    mercredi 1 septembre 2010 16:04
  • Bonjour,

    Je suis pas sûr de comprendre le pb avec cette solution. Gilles donne juste un exemple qui montre qu'il serait possible d'écrire directement un long ("valeur" dans le code originial) sans passer par un tableau intermédiaire. L'ouverture/fermeture de ce flux aurait lieu bien sûr en dehors et non pas dans la boucle.

    "mais mon cas se situe comme je l'ai dit au départ et c'est de ce point de vue que j'ai besoin" Je ne suis pas sûr de comprendre la contrainte que doit respecter la solution (on veut forcément utiliser un tableau intermédaire d'octets ?)

    Choisir un stream permettant d'écrire des long pour pouvoir écrire des longs me parait vraiment le plus logique. Si le passage par un tableau de bytes est obligatoire on pourrait utiliser une union (http://www.dotnet247.com/247reference/msgs/5/27796.aspx) si c'est possible dans ce cas, ou encore utiliser un BinaryWriter sur un "memory stream" juste pour faire cette conversion de long en bytes ou effectivement faire un décalage (mais là c'est un autre sujet si on veut poursuivre sur le problème actuellement rencontré avec les décalages).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    mercredi 1 septembre 2010 17:40
    Modérateur
  • Bonsoir Monsieur SCRIBE,

    je comprends bien les points de vue partagés mais reprenez mon raisonnement de départ Je parle d'une fonction qui retourne une nouvelle construction lorsque celle-ci est appelé dans une boucle, à chaque fois cette fonction construit un tableau donc les précédent sont perdu puisque la fonction (dans la boucle)retourne une nouvelle construction à la même variable donc la mémoire en ai altérée. ce qui ne serait pas le cas si cela passé par une procédure avec un paramètre de retour pour le même tableau, pas de reconstruction, juste une assignation de valeur. Comprenez-vous?

    Ma question est principalement basée sur le décalage de bits pour introduire un long dans un tableau de bits sans passer par une fonction mais plutôt par une procédure.

    imaginons ce qu'il faut pour le même résultat entre une fonction et une procédure avec paramètre de retour? c'est inévitable la procédure est largement plus rapide que la fonction et sans compromettre l'état de la pile

    répondez-moi s'il vous plait c'est important pour moi

    Merci,

     

    mercredi 1 septembre 2010 20:33
  • Bonjour,

    Dans votre cas, vous avez deux solutions :

    Soit vous utilisez le BinaryReader qui s'occupe d'écrire directement un long sur votre fichier (ne fermer le BinaryReader que lorsque vous voulez réellement fermer le flux sur le fichier).

    Soit vous voulez créer un gros tableau intermédiaire dans ce cas, vous avez la méthode Buffer.BlockCopy() qui peut copier un tableau de long en un tableau de byte. Il vous faudra quand même à la fin passer ce tableau à la méthode Write().

    Cordialement


    Gilles TOURREAU - MVP C# - MCTS ADO .NET 3.5 - MCPD Windows Developper 3.5 - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    mercredi 1 septembre 2010 20:49
    Modérateur
  • Bonsoir Monsieur TOURREAU,

    je comprends bien la manipulation mais imaginons que certains cas veuillent lire, supprimer, et réecrire dans le même fichier (comme par exemple le remplacement d'un bitmap en tenant compte que le nouveau ne soit pas de la même longueur et que les suivants référence les mêmes lien situés dans un autre FileStream (les resources sont déjà bien entamée) la solution idéale est de pouvoir faire ce que je demande au départ. Mon problème c'est de convertir un long en un tableau de byte en utilisant les opérateurs de décalage de bits c'est là que je coince  ;-(

    en tout cas chapeau de savoir qu'il y a des gens comme vous pour aider des gens comme nous, et si un jour par un petit miracle je pourrai vous aider, je le fairai de la même manière que vous. c'est à dire avec autant d'ardeur et de conviction.

    Merci

     

    mercredi 1 septembre 2010 21:35
  • Bonjour,

    Dans ce cas, utilisez la méthode suivante :

    Buffer.BlockCopy(mesLongs, indexOctetSource, mesBytes, indexOctetDestination, LongueurCopie)
    

    Rappel : Long = Int64 = 8 octets
    indexOctetSource est l'indice d'octet de départ ou commencer la copie dans le tableau mesLongs.
    indexOctetDestination est l'indice d'octet de départ ou doit être être placé les octets copié
    longueurCopie est le nombre d'octets à copier

    Par exemple : Pour copier le 40ème (position 39 !) long à la case 180 du tableau d'octets (donc le long sera placé entre la case 180 et 187) :

    Buffer.BlockCopy(mesLongs, 39 * 8, mesBytes, 180, 8)
    

    Est-ce que mes explications sont claires et répondent à votre problème ? Cette méthode est très rapide car elle appelle directement du code natif.

    Cordialement


    Gilles TOURREAU - MVP C# - MCTS ADO .NET 3.5 - MCPD Windows Developper 3.5 - Architecte .NET/Consultant/Formateur - http://gilles.tourreau.fr
    jeudi 2 septembre 2010 08:23
    Modérateur
  • Bonjour, j'ai fini par trouver une solution temporaire ne fonctionnant qu'avec les nombres positifs je vous fais part de la procédure en utilisant un ULong au lieu d'un Long:

    Public

     

    Class Form1

     

    Private tamponLong(Len(0L) - 1) As Byte

     

    Private Sub MyBitConverter_GetBits(ByVal valeur As ULong, ByRef tampon() As Byte, ByVal offset As Integer)

    tampon(0) = (valeur << 7 * 8) >> 7 * 8

    tampon(1) = (valeur << 6 * 8) >> 6 * 8 + 1 * 8

    tampon(2) = (valeur << 5 * 8) >> 5 * 8 + 2 * 8

    tampon(3) = (valeur << 4 * 8) >> 4 * 8 + 3 * 8

    tampon(4) = (valeur << 3 * 8) >> 3 * 8 + 4 * 8

    tampon(5) = (valeur << 2 * 8) >> 2 * 8 + 5 * 8

    tampon(6) = (valeur << 1 * 8) >> 1 * 8 + 6 * 8

    tampon(7) = (valeur << 0 * 8) >> 0 * 8 + 7 * 8

     

    End Sub

     

    Private Sub Form1_Shown(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Shown

     

    Dim val As ULong = Long.MaxValue

    MyBitConverter_GetBits(val, tamponLong, 0)

     

    End Sub

    End

     

    Class

    Merci

    • Marqué comme réponse CentSoucis jeudi 2 septembre 2010 08:26
    jeudi 2 septembre 2010 08:24
  • Ok, même si je vois mal l'avantage de la solution des décalages. Cela pourrait donner :

       Dim fs As IO.FileStream
        Dim Data(1) As Long
        Data(0) = &H4142434445464748
        Data(1) = &H4847464544434241
    
        ' Méthode 1
        fs = New IO.FileStream("c:\a.txt", IO.FileMode.Create)
        Dim bw As New IO.BinaryWriter(fs)
        For Each Value As Long In Data
          bw.Write(Value)
        Next
        bw.Close()
    
        ' Méthode 2
        fs = New IO.FileStream("c:\b.txt", IO.FileMode.Create)
        Dim b(7) As Byte
        Dim shift As Integer
        For Each value As Long In Data
          shift = 0
          For i = 0 To 7
            b(i) = (value >> shift) And &HFF
            shift += 8
          Next
          fs.Write(b, 0, 8)
        Next
        fs.Close()
    

    Dans du code normal, ne pas écrite à la racine du disque (un utilisateur non admin n'y a pas les droits).


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    • Marqué comme réponse CentSoucis jeudi 2 septembre 2010 09:40
    jeudi 2 septembre 2010 09:04
    Modérateur
  • Bonjour Monsieur SCRIBE ainsi  qu'à tous,

    La méthode 2 me convient parfaitement et merci pour le And FF et oui bien sûr! Merci beaucoup.

    • Marqué comme réponse CentSoucis jeudi 2 septembre 2010 09:40
    jeudi 2 septembre 2010 09:40
  • J'ai encore un petit truc qui reste en travers °-)

     

    Private Sub MyBitConverter_GetBits(ByVal valeur As Long, ByRef tampon() As Byte, ByVal offset As Integer)

     

    Dim m As ULong = ULong.MaxValue

    tampon(offset + 0) = (valeur

    And &HFFL) >> 0 * 8

    tampon(offset + 1) = (valeur

    And &HFFFFL) >> 1 * 8

    tampon(offset + 2) = (valeur

    And &HFFFFFFL) >> 2 * 8

    tampon(offset + 3) = (valeur

    And &HFFFFFFFFL) >> 3 * 8

    tampon(offset + 4) = (valeur

    And &HFFFFFFFFFF) >> 4 * 8

    tampon(offset + 5) = (valeur

    And &HFFFFFFFFFFFF) >> 5 * 8

    tampon(offset + 6) = (valeur

    And &HFFFFFFFFFFFFFF) >> 6 * 8

     

    Try

    tampon(offset + 7) = (valeur

    And &HFFFFFFFFFFFFFFFF) >> 7 * 8

     

    Catch EX As OverflowException

     

    'le signe moins étant le dernier bit comment écrire le dernier octet?

    MsgBox(

    "comment écrire ce dernier octet?")

     

    End Try

     

    End Sub

    jeudi 2 septembre 2010 13:19
    • Private Sub MyBitConverter_GetBits(ByVal valeur As Long, ByRef tampon() As Byte, ByVal offset As Integer)
    • Dim m As ULong = ULong.MaxValue
    • tampon(offset + 0) = (valeur And &HFFL) >> 0 * 8
    • tampon(offset + 1) = (valeur And &HFFFFL) >> 1 * 8
    • tampon(offset + 2) = (valeur And &HFFFFFFL) >> 2 * 8
    • tampon(offset + 3) = (valeur And &HFFFFFFFFL) >> 3 * 8
    • tampon(offset + 4) = (valeur And &HFFFFFFFFFF) >> 4 * 8
    • tampon(offset + 5) = (valeur And &HFFFFFFFFFFFF) >> 5 * 8
    • tampon(offset + 6) = (valeur And &HFFFFFFFFFFFFFF) >> 6 * 8
    • Try
    • tampon(offset + 7) = (valeur And &HFFFFFFFFFFFFFFFF) >> 7 * 8
    • Catch EX As OverflowException
    • MsgBox( "le signe moins étant le dernier bit comment écrire ce dernier octet?")
    • 'ainsi l'excéption n'aura lieu que pour des valeurs négatives
    • End Try
    • End Sub
    jeudi 2 septembre 2010 13:27
  • Je pense que le problème est qu'il faut utiliser &HFFFFFFFFFFFFFFFFUL, le UL qui suit le nombre permettant d'indiquer que la valeur littérale est un "ulong" et non pas un "long".

     


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    jeudi 2 septembre 2010 15:49
    Modérateur
  • j'ai essayé le UL , mais l'expression constante n'est pas représentable dans le type Long. Cala est dû à ce que valeur est un long. Il faut interpréter le dernier octet pour l'inscrire dans un byte. C'est un un peu tiré par les cheuveux, mais dès que c'est fait, c'est une bombe, la rapidité (sans jouer avec les pointeurs) ni les boucles seul inconvénient c'est l'exception pour les nombres négatifs mais bon c'est rare dans un transfère vers un stream.
    • Modifié CentSoucis jeudi 2 septembre 2010 18:06
    jeudi 2 septembre 2010 16:59
  • Au temps pour moi. J'avais regardé trop vite et le m ulong non utilisé m'a fait croire que l'on travaillait sur du ulong maintenant...

    Donc en regardant de plus près, je pense que le plus simple est de faire comme je le faisais dans mon code précédent c'est-à-dire de faire d'abord le décalage puis de garder l'octet de poids faible. Comme on ne fait que des "And &hFF" du coup, le signe est toujours supprimé (les décalages préservent le signe donc le dernier And ne sert à rien car on garde de toute façon tous les bits y compris le signe puis on décale et on a toujours le signe ce qui fait échouer l'affectation vers l'octet non signé).

    J'ai vu aussi le message à Gilles qui évoque un contexte particulier (travail sur un bitmap ?) mais ce n'est peut-être qu'à titre d'exemple ? Parfois il est intéressant de donner le contexte exact car cela permet de faire des suggestions plus pertinentes. Par exemple la méthode de l'"union" que j'ai évoqué précédemment pourrait permettre de voir les mêmes données en permanence à la fois sous forme d'un tableau de double et d'octets sans faire aucune copie. Par contre cela dépend effectivement du contexte (selon que l'on fait une "copie" une fois pour toute d'une source vers une destination où on travaille en permanence sur une même zone mémoire que l'on veut accéder différemment selon les besoins). Donc il est parfois intéressant de donner un peu plus de détails sur le contexte exact ce qui peut susciter d'autres approches...

     


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    jeudi 2 septembre 2010 18:03
    Modérateur
  •  

    Private Sub MyBitConverter_GetBits(ByVal valeur As Long, ByRef tampon() As Byte, ByVal offset As Integer)

    tampon(offset + 0) = (valeur

    And &HFFL) >> 0 * 8

    tampon(offset + 1) = (valeur

    And &HFFFFL) >> 1 * 8

    tampon(offset + 2) = (valeur

    And &HFFFFFFL) >> 2 * 8

    tampon(offset + 3) = (valeur

    And &HFFFFFFFFL) >> 3 * 8

    tampon(offset + 4) = (valeur

    And &HFFFFFFFFFF) >> 4 * 8

    tampon(offset + 5) = (valeur

    And &HFFFFFFFFFFFF) >> 5 * 8

    tampon(offset + 6) = (valeur

    And &HFFFFFFFFFFFFFF) >> 6 * 8

     

    Try

    tampon(offset + 7) = (valeur

    And &HFFFFFFFFFFFFFFFF) >> 7 * 8

     

    Catch EX As OverflowException

    tampon(offset + 7) =

    Not valeur >> 7 * 8

    tampon(offset + 7) = tampon(offset + 7)

    Or &HFF

     

    End Try

     

    End Sub

    Voilà, grace à vous le problème est résolu.

    Je vous remercie beaucoup et à bientôt pour de nouvelle aventure

    • Marqué comme réponse CentSoucis vendredi 3 septembre 2010 06:49
    vendredi 3 septembre 2010 06:47
  • erreur dans le catch: correction

    Catch EX As OverflowException

    tampon(offset + 7) =

    Not valeur >> 7 * 8

    tampon(offset + 7) =

    Not tampon(offset + 7)

     

    End Try

    Mille fois merci

    • Marqué comme réponse CentSoucis vendredi 3 septembre 2010 07:47
    vendredi 3 septembre 2010 07:37
  • Content de voir que c'est résolu mais pourquoi ne jamais choisir la solution la plus simple ;-)


    Please always mark whatever response solved your issue so that the thread is properly marked as "Answered".
    vendredi 3 septembre 2010 09:17
    Modérateur
  • c'est la soultion la plus simple! ;-) il n'y a pas mieux !

     

    vendredi 3 septembre 2010 10:51