ฉันจะแปลงlong
a byte[]
และกลับเป็น Java ได้อย่างไร
ฉันพยายามแปลง a เป็นlong
a byte[]
เพื่อที่ฉันจะสามารถส่งbyte[]
ผ่านการเชื่อมต่อ TCP ในอีกด้านหนึ่งผมอยากจะใช้เวลาที่และแปลงกลับเป็นbyte[]
double
ฉันจะแปลงlong
a byte[]
และกลับเป็น Java ได้อย่างไร
ฉันพยายามแปลง a เป็นlong
a byte[]
เพื่อที่ฉันจะสามารถส่งbyte[]
ผ่านการเชื่อมต่อ TCP ในอีกด้านหนึ่งผมอยากจะใช้เวลาที่และแปลงกลับเป็น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();
}
หรือห่อในชั้นเรียนเพื่อหลีกเลี่ยงการสร้าง ByteBuffers ซ้ำ ๆ :
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();
}
}
เนื่องจากสิ่งนี้กำลังได้รับความนิยมอย่างมากฉันแค่พูดถึงว่าฉันคิดว่าคุณควรใช้ห้องสมุดอย่าง Guava ในกรณีส่วนใหญ่ และหากคุณมีข้อคัดค้านที่แปลกประหลาดกับห้องสมุดคุณควรพิจารณาคำตอบนี้ก่อนสำหรับวิธีแก้ปัญหาภาษาจาวา ฉันคิดว่าสิ่งสำคัญที่คำตอบของฉันเป็นจริงคือคุณไม่ต้องกังวลเกี่ยวกับ endian-ness ของระบบด้วยตัวเอง
ฉันทดสอบเมธอด ByteBuffer จากการใช้งาน bitwise ธรรมดา แต่วิธีหลังนั้นเร็วกว่ามาก
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]
ค่าไบต์จะถูกแปลงเป็นความยาวซึ่งจะขยายส่วนขยายของสัญญาณ ไบต์ที่มีค่า -128 (ฐานสิบหก0x80
) จะเปลี่ยนเป็นความยาวที่มีค่า -128 (ฐานสิบหก0xFFFF FFFF FFFF FF80
) ก่อนอื่นหลังจากการแปลงคือค่าหรือ: ed เข้าด้วยกัน โดยใช้ค่าที่เหมาะสมและป้องกันการนี้โดยแปลงแรกไบต์เป็น int (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80
และตัดออกจากการขยายเข้าสู่ระบบ: ทำไมไบต์ที่ลงชื่อเข้าใช้จาวาเป็นเรื่องลึกลับสำหรับฉัน แต่ฉันคิดว่ามันเหมาะกับประเภทอื่น ๆ
หากคุณกำลังมองหาเวอร์ชั่นที่ยังไม่ได้เผยแพร่อย่างรวดเร็วสิ่งนี้ควรทำเคล็ดลับโดยสมมติว่าอาร์เรย์ไบต์เรียกว่า "b" ซึ่งมีความยาว 8:
ไบต์ [] -> ยาว
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);
ยาว -> ไบต์ []เป็นคู่ที่แน่นอนกับข้างต้น
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)};
ทำไมคุณต้องมีไบต์ [] ทำไมไม่เขียนลงในซ็อกเก็ต?
ฉันถือว่าคุณหมายถึงความยาวมากกว่ายาวความหลังจำเป็นต้องยอมให้มีค่าว่าง
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
ตามเอกสาร"ลำดับเริ่มต้นของบัฟเฟอร์ไบต์มักจะเป็น BIG_ENDIAN
เพียงแค่เขียนยาวไปDataOutputStreamกับพื้นฐานByteArrayOutputStream จาก ByteArrayOutputStream คุณสามารถรับ byte-array ผ่าน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 คุณไม่จำเป็นต้องใช้ไบต์ [] ด้วยตนเอง คุณจะใช้ซ็อกเก็ต 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 อาจให้ผลลัพธ์ที่ไม่ถูกต้องตราบใดที่คุณรู้ว่าคุณกำลังทำงานกับสตริง "ปกติ" นี่เป็นวิธีการที่จะเพิ่มประสิทธิภาพและทำให้รหัสง่ายขึ้นซึ่งในทางกลับกันจะต้องใช้สมมติฐานบางอย่างกับสายข้อมูลที่ทำงานอยู่
ข้อเสียของการใช้วิธีนี้:หากคุณกำลังทำงานกับอักขระ ASCII บางตัวเช่นสัญลักษณ์เหล่านี้ในตอนต้นของตาราง ASCII บรรทัดต่อไปนี้อาจล้มเหลว แต่ลองมาดูกัน - คุณอาจไม่เคยใช้เลย
Pro ของการใช้วิธีนี้:จำไว้ว่าคนส่วนใหญ่มักจะทำงานกับสายปกติโดยไม่ต้องมีตัวอักษรผิดปกติใด ๆ แล้ววิธีนี้เป็นวิธีที่ง่ายและรวดเร็วที่สุดในการไป
จากยาวเป็นไบต์ []:
byte[] arr = String.valueOf(longVar).getBytes();
จากไบต์ [] ถึงยาว:
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:
นี่เป็นอีกวิธีในการแปลงbyte[]
เป็นlong
โดยใช้ Java 8 หรือใหม่กว่า:
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
สามารถแสดงเป็นบิตสูงและต่ำตามลำดับของค่าจำนวนเต็มสองค่าซึ่งขึ้นอยู่กับ bitwise-OR โปรดทราบว่าtoUnsignedLong
มาจากInteger
ชั้นเรียนและสายแรกที่toUnsignedLong
อาจจะฟุ่มเฟือย
การแปลงตรงกันข้ามสามารถ unrolled เช่นกันตามที่คนอื่น ๆ ได้กล่าวถึง
ส่วนขยาย Kotlin สำหรับประเภท Long และ ByteArray:
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