2011-11-14 2 views
4

숫자 값을 바이트 배열로 변환해야합니다. 예를 들어, 바이트 배열로 긴 변환, 나는이 방법을 가지고 :이 Java ByteBuffer의 동작에 대한 설명이 있습니까?

public static byte[] longToBytes(long l) { 
    ByteBuffer buff = ByteBuffer.allocate(8); 

    buff.order(ByteOrder.BIG_ENDIAN); 

    buff.putLong(l); 

    return buff.array(); 
} 

그것은 매우 간단합니다 - 그것은을 저장할 수있는 배열을 할당이 오래 걸릴 거기에 그것을 던져. l의 값이 무엇인지에 관계없이, 나는 8 바이트 배열을 가져와서 처리하고 의도 한대로 사용할 수 있습니다. 필자는 맞춤 바이너리 형식을 만든 다음 네트워크를 통해 전송합니다.

값이 773450364 인이 메서드를 호출하면 [0 0 0 0 46 25 -22 124] 배열이 반환됩니다. I 다시이 방법으로, 다른 방법에서 배열을 전달할 때

public static Long bytesToLong(byte[] aBytes, int start) { 
    byte[] b = new byte[8]; 

    b[0] = aBytes[start + 0]; 
    b[1] = aBytes[start + 1]; 
    b[2] = aBytes[start + 2]; 
    b[3] = aBytes[start + 3]; 
    b[4] = aBytes[start + 4]; 
    b[5] = aBytes[start + 5]; 
    b[6] = aBytes[start + 6]; 
    b[7] = aBytes[start + 7]; 

    ByteBuffer buf = ByteBuffer.wrap(b); 
return buf.getLong(); 
} 

, 난 773,450,364 얻을 정확 : I는 다시 그들의 수치로 바이트 배열 변환 코드를 갖는다.

이제이 배열을 TCP를 통해 다른 Java 클라이언트에 전송합니다. java.io.InputStream.read() 메서드에 대한 설명서에 따르면 스트림 끝에 도달하고 -1이 반환되지 않는 한 int 값은 0에서 255 사이의 값을 반환합니다. 그러나 바이트 배열을 채우는 데 사용할 때받는 쪽에서 음수 값을 계속 가져옵니다. 이 오버플로 함께 할 수있는 용의자 (255 값을 Java 바이트에 맞지 않을 수 있으므로 바이트 배열에 넣을 때, 오버플로 및 음수가 될).

이것은 내 문제를 야기합니다. 음수의 존재는 나를 염려합니다. 지금은 바이트 수가 -128에서 127 사이 인 응용 프로그램의 Java 측을 개발 중입니다. 다른 끝점은 C, C++, Python, Java, C# ...이 될 수 있습니다. 일부 바이트 배열에서 음수 값의 존재가 처리에 어떻게 영향을 미치는지 확실하지 않습니다. 이 동작을 문서화하는 것 외에,이 시스템에서 작업하는 나 자신과 미래의 개발자, 특히 Java로 작성되지 않은 끝점에서 더 쉽게 만들 수 있습니까?

+0

ByteBuffer의 endianness를'bytesToLong' 메소드에서'getToGong'과 같이'getLong()'을 호출하기 전에 설정하지 않아야합니까? 귀하의 질문에 정말로 관련이 없습니다. 궁금한 점이 있으시면 ... –

+0

@G_H 나는 그것을 조사하고 테스트해야합니다. 실제로 이러한 방법 중 하나를 직접 작성하지 않았으며 테스트 사례가 부족합니다. 그 점을 지적 해 주셔서 감사합니다. –

답변

6

자바의 byte은 8 비트 two's complement 형식으로 표시됩니다. 범위가 128 - 255이고 범위를 byteint으로 설정하면 음수 값 (-1에서 -128 사이) 인 byte이됩니다.

바이트를 읽은 후 byte으로 변환하기 전에 -1 인지 확인해야합니다. 이 메서드가 byte이 아닌 int을 반환하는 이유는 byte으로 변환하기 전에 end-of-stream을 확인할 수 있도록하기 위해서입니다.

또 다른 한 가지 : bytesToLong 방법으로 aBytes 어레이를 복사하는 이유는 무엇입니까? 당신은 상당히 그 방법을 단순화하고 unncessary 사본을 저장할 수 있습니다

public static Long bytesToLong(byte[] aBytes, int start) { 
    return ByteBuffer.wrap(aBytes, start, 8).order(ByteOrder.BIG_ENDIAN).getLong(); 
} 
1

모두 당신의 전송 및 수신 엔드 포인트가 현재 자바로 구현됩니다. 수신 측에 InputStream을, 수신 측에 OutputStream을 사용하고 있다고 가정합니다. 기본 소켓 구현 세부 사항을 잠시 신뢰할 수 있다고 가정하면 소켓을 통해 전송 된 모든 바이트가 대상에 정확히 도착하도록 고려할 것입니다.

그래서 OutputStream에 무언가를 버릴 때 Java 레벨에서 실제로 어떻게됩니까?the JavaDoc for a method writing a byte array을 확인하면 스트림을 통해 바이트가 전송된다는 것을 알 수 있습니다. 거기에 주요한 건 없어요. 하지만 method taking an int as argument에 대한 문서를 확인하면이 int가 실제로 어떻게 쓰여지는지 자세히 알 수 있습니다. 하위 8 비트는 스트림을 통해 바이트로 보내지 만 고위 24 비트 (int는 Java에서 32 비트 표현)은 단순히 무시됩니다.

수신 측에 있습니다. 당신은 InputStream을 가지고 있습니다. one of the methods reading directly into a byte array을 사용하지 않으면 int가 제공됩니다. Like the doc says의 경우 int는 0에서 255 사이의 값이거나 스트림의 끝에 도달하면 -1입니다. 이것은 중요한 비트입니다. 한편으로는, 가능한 모든 1 바이트의 비트 패턴을 InputStream로부터 읽어 낼 수가 있습니다. 그러나 읽기가 더 이상 의미있는 값을 반환 할 수없는 경우를 감지 할 수있는 방법이 필요합니다. 그래서이 메소드는 바이트가 아닌 int를 반환합니다 ... -1 값은 스트림의 끝에 도달했음을 나타내는 플래그입니다. -1 이외의 것을 얻는다면 관심있는 유일한 것은 하위 8 비트입니다. 이들은 임의의 비트 패턴 일 수 있기 때문에, 십진수 값은 -128에서부터 127까지입니다. int 대신 int 대신에 바이트 배열을 직접 읽어 보면 "트리밍"이 수행됩니다. 그래서 당신은 그 부정적인 가치들을 보게 될 것입니다. 즉, 자바가 부호있는 십진수로 바이트를 표시하는 방식 때문에 부정적인 것입니다. 관심있는 유일한 것은 실제 비트 패턴입니다. 모두 당신이 전형적인의 InputStream 한 번에 한 바이트를 사용하여 루프를 읽을 수 1255

에 255 또는 1000에 값 0을 나타낼 수 있습니다 관심은이 같은 거보기 :

InputStream ips = ...; 
int read = 0; 
while((read = ips.read()) != -1) { 
    byte b = (byte)read; 
    //b will now have a bit pattern ranging from 0x00 to 0xff in hex, or -128 to 127 in two-complement signed representation 
} 

실행, 다음

public class Main { 

    public static void main(String[] args) { 

     final int i1 = Ox00_00_00_fe; 
     final int i1 = Ox80_00_00_fe; 

     final byte b1 = (byte)i1; 
     final byte b2 = (byte)i2; 

     System.out.println(i1); 
     System.out.println(i2); 

     System.out.println(b1); 
     System.out.println(b2); 

     final int what = Ox12_34_56_fe; 
     final byte the_f = (byte)what; 

     System.out.println(what); 
     System.out.println(the_f); 

    } 

} 

으로 단순히 최하위 8 비트 아무것도하지만, 도랑 것 바이트 INT에서 캐스팅이 분명있을 것입니다 : 조명한다 (자바 7 INT 리터럴 사용). 따라서 int는 양수 또는 음수 일 수 있으며 바이트 값에 영향을주지 않습니다. 오직 마지막 8 비트.

짧은 이야기 : InputStream에서 올바른 바이트 값을 얻고 있습니다. 여기서 실질적인 걱정은 클라이언트 측이 어떤 프로그래밍 언어로도 작성되고 모든 플랫폼에서 실행될 수 있다면 문서에서 수신 된 바이트가 무엇을 의미하는지, 그리고 이것이 long 일 경우 어떻게 작성해야 하는지를 분명히해야합니다. 인코딩됩니다. 특정 엔디안의 ByteBufferputLong 메소드를 사용하여 인코딩이 Java로 이루어 졌음을 분명히하십시오. 그런 다음에는 그 바이트를 해석하는 방법을 절대적으로 확신 할 수있는 정보 (Java 스펙과 결합 된 정보)를 갖게됩니다.

0

모든 데이터가 빅 엔디안이라면이 모든 문제를 해결하고 DataOutputStream을 사용할 수 있습니다. 그것은 당신이 필요로하는 모든 것을 가지고 있습니다.

+0

불행히도, 그것은 모든 빅 엔디 언이 아닙니다. –

관련 문제