web-dev-qa-db-fra.com

Convertir 4 octets en int

Je lis un fichier binaire comme ceci:

InputStream in = new FileInputStream( file );
byte[] buffer = new byte[1024];
while( ( in.read(buffer ) > -1 ) {

   int a = // ??? 
}

Ce que je veux faire, c'est lire jusqu'à 4 octets et créer une valeur int à partir de ceux-ci, mais je ne sais pas comment le faire. 

J'ai l'impression de devoir saisir 4 octets à la fois et de réaliser une opération "octet" (comme >> << & FF, etc.) pour créer le nouvel int 

Quel est l'idiome pour cela? 

MODIFIER

Oups, cela s'avère un peu plus complexe (pour expliquer) 

Ce que j'essaie de faire est de lire un fichier (peut-être ascii, binaire, peu importe) et d'extraire les entiers qu'il peut avoir. 

Par exemple, supposons que le contenu binaire (en base 2):

00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000010

La représentation entière devrait être 1, 2 non? : -/1 pour les 32 premiers bits et 2 pour les 32 bits restants. 

11111111 11111111 11111111 11111111

Serait -1 

et 

01111111 11111111 11111111 11111111

Serait Integer.MAX_VALUE ( 2147483647 ) 

66
OscarRyz

ByteBuffer a cette capacité et est capable de travailler avec des entiers petit et grand endian.

Considérons cet exemple:


//  read the file into a byte array
File file = new File("file.bin");
FileInputStream fis = new FileInputStream(file);
byte [] arr = new byte[(int)file.length()];
fis.read(arr);

//  create a byte buffer and wrap the array
ByteBuffer bb = ByteBuffer.wrap(arr);

//  if the file uses little endian as apposed to network
//  (big endian, Java's native) format,
//  then set the byte order of the ByteBuffer
if(use_little_endian)
    bb.order(ByteOrder.LITTLE_ENDIAN);

//  read your integers using ByteBuffer's getInt().
//  four bytes converted into an integer!
System.out.println(bb.getInt());

J'espère que cela t'aides.

66
Tom

Vous devriez le mettre dans une fonction comme celle-ci:

public static int toInt(byte[] bytes, int offset) {
  int ret = 0;
  for (int i=0; i<4 && i+offset<bytes.length; i++) {
    ret <<= 8;
    ret |= (int)bytes[i] & 0xFF;
  }
  return ret;
}

Exemple:

byte[] bytes = new byte[]{-2, -4, -8, -16};
System.out.println(Integer.toBinaryString(toInt(bytes, 0)));

Sortie:

11111110111111001111100011110000

Cela permet de manquer d'octets et de gérer correctement les valeurs d'octet négatives.

Je ne suis pas au courant d'une fonction standard pour le faire.

Points à considérer:

  1. Endianness: différentes architectures de CPU placent les octets constituant un int dans des ordres différents. En fonction de la manière dont vous créez le tableau d'octets, vous devrez peut-être vous en préoccuper. et

  2. Buffering: si vous saisissez 1024 octets à la fois et démarrez une séquence à l'élément 1022, vous frapperez la fin du tampon avant d'obtenir 4 octets. Il est probablement préférable d'utiliser une forme de flux d'entrée en mémoire tampon qui le fait automatiquement afin que vous puissiez simplement utiliser readByte() à plusieurs reprises et ne pas vous en préoccuper autrement.

  3. Trailing Buffer: la fin de l’entrée peut être un nombre impair d’octets (pas un multiple de 4 spécifiquement) selon la source. Mais si vous créez l'entrée pour commencer et qu'il est "garanti" (ou au moins une condition préalable) d'être un multiple de 4, vous n'aurez peut-être pas à vous en préoccuper.

pour en savoir plus sur le point de mise en mémoire tampon, considérons le BufferedInputStream :

InputStream in = new BufferedInputStream(new FileInputStream(file), 1024);

Vous avez maintenant une InputStream qui automatiquement tamponne 1024 octets à la fois, ce qui est beaucoup moins difficile à gérer. De cette façon, vous pouvez lire 4 octets à la fois et ne pas vous inquiéter de trop d'E/S.

Deuxièmement, vous pouvez aussi utiliser DataInputStream :

InputStream in = new DataInputStream(new BufferedInputStream(
                     new FileInputStream(file), 1024));
byte b = in.readByte();

ou même:

int i = in.readInt();

et ne vous inquiétez pas de la construction de ints du tout.

27
cletus

Si vous les avez déjà dans un tableau d'octets [], vous pouvez utiliser: 

int result = ByteBuffer.wrap(bytes).getInt();

source: ici

26
iTEgg

il suffit de voir comment DataInputStream.readInt () est implémenté;

    int ch1 = in.read();
    int ch2 = in.read();
    int ch3 = in.read();
    int ch4 = in.read();
    if ((ch1 | ch2 | ch3 | ch4) < 0)
        throw new EOFException();
    return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
14

Le moyen le plus simple est:

RandomAccessFile in = new RandomAccessFile("filename", "r"); 
int i = in.readInt();

-- ou --

DataInputStream in = new DataInputStream(new BufferedInputStream(
    new FileInputStream("filename"))); 
int i = in.readInt();
5
Taylor Leese

essayez quelque chose comme ça:

a = buffer[3];
a = a*256 + buffer[2];
a = a*256 + buffer[1];
a = a*256 + buffer[0];

cela suppose que l'octet le plus bas vient en premier. si l'octet le plus élevé vient en premier, vous devrez peut-être échanger les index (passez de 0 à 3).

en gros, pour chaque octet que vous souhaitez ajouter, vous devez tout d'abord multiplier a par 256 (ce qui correspond à un décalage de 8 bits vers la gauche), puis ajouter le nouvel octet.

4
stmax

Vous pouvez également utiliser BigInteger pour les octets de longueur variable. Vous pouvez le convertir en long, entier ou court, selon vos besoins.

new BigInteger(bytes).intValue();

ou pour désigner la polarité:

new BigInteger(1, bytes).intValue();
1
Jamel Toms
for (int i = 0; i < buffer.length; i++)
{
   a = (a << 8) | buffer[i];
   if (i % 3 == 0)
   {
      //a is ready
      a = 0;
   }       
}
1
Andrey

Conversion d'un tableau de 4 octets en entier:

//Explictly declaring anInt=-4, byte-by-byte
byte[] anInt = {(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xfc}; // Equals -4
//And now you have a 4-byte array with an integer equaling -4...
//Converting back to integer from 4-bytes...
result = (int) ( anInt[0]<<24 | ( (anInt[1]<<24)>>>8 ) | ( (anInt[2]<<24)>>>16) | ( (anInt[3]<<24)>>>24) );
0
mark_infinite

Le code suivant lit 4 octets à partir de array (un byte[]) à la position index et renvoie une int. J'ai essayé la plupart du code des autres réponses sur Java 10 et quelques autres variantes que j'avais imaginées.

Ce code utilise le moins de temps CPU possible, mais alloue une ByteBuffer jusqu'à ce que le JIT de Java 10 supprime cette allocation.

int result;

result = ByteBuffer.
   wrap(array).
   getInt(index);

Ce code est le code le plus performant qui n’alloue rien. Malheureusement, il consomme 56% de temps processeur de plus par rapport au code ci-dessus.

int result;
short data0, data1, data2, data3;

data0  = (short) (array[index++] & 0x00FF);
data1  = (short) (array[index++] & 0x00FF);
data2  = (short) (array[index++] & 0x00FF);
data3  = (short) (array[index++] & 0x00FF);
result = (data0 << 24) | (data1 << 16) | (data2 << 8) | data3;
0
Nathan

Pour lire les 4 octets non signés sous forme d'entier, nous devrions utiliser une variable longue, car le bit de signe est considéré comme faisant partie du nombre non signé.

long result = (((bytes[0] << 8 & bytes[1]) << 8 & bytes[2]) << 8) & bytes[3]; 
result = result & 0xFFFFFFFF;

Ceci est testé fonction bien travaillée

0
Mounir