Java에서 a long
를 a 로 변환하고 어떻게 byte[]
다시 변환 합니까?
TCP 연결을 통해 보낼 수 있도록 a long
를 로 변환하려고 합니다. 다른 쪽에서는 그것을 가져 와서 다시로 변환 하고 싶습니다 .byte[]
byte[]
byte[]
double
Java에서 a long
를 a 로 변환하고 어떻게 byte[]
다시 변환 합니까?
TCP 연결을 통해 보낼 수 있도록 a long
를 로 변환하려고 합니다. 다른 쪽에서는 그것을 가져 와서 다시로 변환 하고 싶습니다 .byte[]
byte[]
byte[]
double
답변:
public byte[] longToBytes(long x) {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(x);
return buffer.array();
}
public long bytesToLong(byte[] bytes) {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.put(bytes);
buffer.flip();//need flip
return buffer.getLong();
}
또는 ByteBuffer를 반복적으로 생성하지 않도록 클래스에 래핑하십시오.
public class ByteUtils {
private static ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
public static byte[] longToBytes(long x) {
buffer.putLong(0, x);
return buffer.array();
}
public static long bytesToLong(byte[] bytes) {
buffer.put(bytes, 0, bytes.length);
buffer.flip();//need flip
return buffer.getLong();
}
}
이것이 인기가 있기 때문에 대다수의 경우 구아바와 같은 라이브러리를 사용하는 것이 더 좋다고 생각합니다. 그리고 라이브러리에 대한 이상한 반대가 있다면 네이티브 Java 솔루션에 대해이 답변을 먼저 고려해야 합니다 . 내 대답은 실제로 시스템의 엔디안 자체에 대해 걱정할 필요가 없다는 것입니다.
평범한 비트 연산에 대해 ByteBuffer 메서드를 테스트했지만 후자가 훨씬 빠릅니다.
public static byte[] longToBytes(long l) {
byte[] result = new byte[8];
for (int i = 7; i >= 0; i--) {
result[i] = (byte)(l & 0xFF);
l >>= 8;
}
return result;
}
public static long bytesToLong(final byte[] bytes, final int offset) {
long result = 0;
for (int i = offset; i < Long.BYTES + offset; i++) {
result <<= Long.BYTES;
result |= (bytes[i] & 0xFF);
}
return result;
}
result |= b[i]
바이트 단위는 바이트 값만 long으로 변환되어 부호 확장을 나타 내기 때문에 비트 단위로 중요 합니다. 값이 -128 (hex 0x80
) 인 바이트는 값이 -128 (hex ) 인 long으로 바뀝니다 0xFFFF FFFF FFFF FF80
. 변환 후 첫 번째 값은 다음과 같습니다. 비트 단위를 사용하면 먼저 바이트를 int로 변환하고 부호 확장을 잘라서이를 방지합니다 (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80
. 바이트가 java로 서명 된 이유는 나에게 약간의 미스터리이지만 다른 유형과도 일치한다고 생각합니다.
빠른 롤링되지 않은 버전을 찾고 있다면 길이가 8 인 "b"라는 바이트 배열을 가정하여 트릭을 수행해야합니다.
바이트 []-> 긴
long l = ((long) b[7] << 56)
| ((long) b[6] & 0xff) << 48
| ((long) b[5] & 0xff) << 40
| ((long) b[4] & 0xff) << 32
| ((long) b[3] & 0xff) << 24
| ((long) b[2] & 0xff) << 16
| ((long) b[1] & 0xff) << 8
| ((long) b[0] & 0xff);
위의 정확한 대응 물인 long- > byte []
byte[] b = new byte[] {
(byte) lng,
(byte) (lng >> 8),
(byte) (lng >> 16),
(byte) (lng >> 24),
(byte) (lng >> 32),
(byte) (lng >> 40),
(byte) (lng >> 48),
(byte) (lng >> 56)};
바이트 []가 왜 필요한가요? 왜 소켓에 쓰지 않습니까?
Long 대신 long 을 의미한다고 가정 하고 후자는 null 값을 허용해야합니다.
DataOutputStream dos = new DataOutputStream(
new BufferedOutputStream(socket.getOutputStream()));
dos.writeLong(longValue);
DataInputStream dis = new DataInputStream(
new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();
byte[]
그 목적을위한 수단 일뿐입니다.
ByteBuffer
워드 프로세서에 따라하는 "byte 버퍼의 초기 순서는 항상 BIG_ENDIAN입니다.
기본 ByteArrayOutputStream 을 사용하여 Long을 DataOutputStream에 작성하십시오 . ByteArrayOutputStream에서 toByteArray () 를 통해 바이트 배열을 얻을 수 있습니다 .
class Main
{
public static byte[] long2byte(long l) throws IOException
{
ByteArrayOutputStream baos=new ByteArrayOutputStream(Long.SIZE/8);
DataOutputStream dos=new DataOutputStream(baos);
dos.writeLong(l);
byte[] result=baos.toByteArray();
dos.close();
return result;
}
public static long byte2long(byte[] b) throws IOException
{
ByteArrayInputStream baos=new ByteArrayInputStream(b);
DataInputStream dos=new DataInputStream(baos);
long result=dos.readLong();
dos.close();
return result;
}
public static void main (String[] args) throws java.lang.Exception
{
long l=123456L;
byte[] b=long2byte(l);
System.out.println(l+": "+byte2long(b));
}
}
그에 따라 다른 프리미티브에 적용됩니다.
힌트 : TCP의 경우 수동으로 byte []가 필요하지 않습니다. 소켓 socket
과 그 스트림을 사용합니다
OutputStream os=socket.getOutputStream();
DataOutputStream dos=new DataOutputStream(os);
dos.writeLong(l);
//etc ..
대신에.
org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html 에서 구현을 사용할 수 있습니다 .
소스 코드는 다음과 같습니다.
toLong 및 toBytes 메소드를 찾으십시오.
소프트웨어 라이센스를 사용하면 코드의 일부를 사용하여 사용할 수 있지만이를 확인하십시오.
public static long bytesToLong(byte[] bytes) {
if (bytes.length > 8) {
throw new IllegalMethodParameterException("byte should not be more than 8 bytes");
}
long r = 0;
for (int i = 0; i < bytes.length; i++) {
r = r << 8;
r += bytes[i];
}
return r;
}
public static byte[] longToBytes(long l) {
ArrayList<Byte> bytes = new ArrayList<Byte>();
while (l != 0) {
bytes.add((byte) (l % (0xff + 1)));
l = l >> 8;
}
byte[] bytesp = new byte[bytes.size()];
for (int i = bytes.size() - 1, j = 0; i >= 0; i--, j++) {
bytesp[j] = bytes.get(i);
}
return bytesp;
}
나는 가능한 가장 빠른 ׂ (예, 허용 된 답변보다 더 많은) 인 또 다른 답변을 추가 할 것입니다. 그러나 모든 경우에 적용되지는 않습니다. 그러나 모든 가능한 시나리오에서 작동합니다.
단순히 문자열을 중간으로 사용할 수 있습니다. String을 사용하면 "NORMAL"문자열로 작업하고 있다는 것을 알면 오랫동안 잘못된 결과를 얻을 수있는 것처럼 보이지만 올바른 결과를 얻을 수 있습니다. 이것은 효과를 높이고 코드를 더 단순하게 만드는 방법으로, 결과적으로 작동하는 데이터 문자열에 대한 몇 가지 가정을 사용해야합니다.
이 방법 사용의 단점 : ASCII 표의 시작 부분에서 이러한 기호와 같은 일부 ASCII 문자로 작업하는 경우 다음 줄이 실패 할 수 있지만 직면 해 보자. 어쨌든 절대로 사용하지는 않을 것입니다.
이 방법을 사용하는 장점 : 대부분의 사람들은 일반적으로 특이한 문자없이 일부 일반 문자열로 작업하며이 방법이 가장 간단하고 빠른 방법임을 기억하십시오.
Long에서 byte []로 :
byte[] arr = String.valueOf(longVar).getBytes();
byte []에서 Long으로 :
long longVar = Long.valueOf(new String(byteArr)).longValue();
OutputStream
소켓에 쓰기 위해 이미를 사용하고 있다면 DataOutputStream 이 적합 할 수 있습니다. 예를 들면 다음과 같습니다.
// Assumes you are currently working with a SocketOutputStream.
SocketOutputStream outputStream = ...
long longValue = ...
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeLong(longValue);
dataOutputStream.flush();
비슷한 방법이 있습니다 short
, int
, float
, 등 그런 다음 사용할 수 의 DataInputStream를 수신 측에이.
ByteBuffer.allocate (8) .putLong (obj) .array () 사용시 :
public byte[] toBytes(Long obj) {
if (obj != null) {
return ByteBuffer.allocate(8).putLong(obj).array();
return null;
}
출처:
ByteBuffer의 다른 많은 사용 예제의 경우 :
다음은 Java 8 이상 byte[]
을 long
사용하여 변환 하는 다른 방법입니다 .
private static int bytesToInt(final byte[] bytes, final int offset) {
assert offset + Integer.BYTES <= bytes.length;
return (bytes[offset + Integer.BYTES - 1] & 0xFF) |
(bytes[offset + Integer.BYTES - 2] & 0xFF) << Byte.SIZE |
(bytes[offset + Integer.BYTES - 3] & 0xFF) << Byte.SIZE * 2 |
(bytes[offset + Integer.BYTES - 4] & 0xFF) << Byte.SIZE * 3;
}
private static long bytesToLong(final byte[] bytes, final int offset) {
return toUnsignedLong(bytesToInt(bytes, offset)) << Integer.SIZE |
toUnsignedLong(bytesToInt(bytes, offset + Integer.BYTES));
}
a long
를 변환하는 것은 비트 OR 연산을받는 두 정수 값의 상위 및 하위 비트로 표현 될 수 있습니다. (가) 있습니다 toUnsignedLong
으로부터입니다 Integer
클래스와의 최초의 호출은 toUnsignedLong
불필요 할 수있다.
다른 사람들이 언급했듯이 반대 변환도 풀 수 있습니다.
Long 및 ByteArray 유형에 대한 Kotlin 확장 :
fun Long.toByteArray() = numberToByteArray(Long.SIZE_BYTES) { putLong(this@toByteArray) }
private inline fun numberToByteArray(size: Int, bufferFun: ByteBuffer.() -> ByteBuffer): ByteArray =
ByteBuffer.allocate(size).bufferFun().array()
@Throws(NumberFormatException::class)
fun ByteArray.toLong(): Long = toNumeric(Long.SIZE_BYTES) { long }
@Throws(NumberFormatException::class)
private inline fun <reified T: Number> ByteArray.toNumeric(size: Int, bufferFun: ByteBuffer.() -> T): T {
if (this.size != size) throw NumberFormatException("${T::class.java.simpleName} value must contains $size bytes")
return ByteBuffer.wrap(this).bufferFun()
}
내 라이브러리에서 전체 코드를 볼 수 있습니다 https://github.com/ArtemBotnev/low-level-extensions