मैं लांग बाइट को [] और बैक में जावा में कैसे परिवर्तित करूं


159

मैं जावा में longbyte[]और बैक को कैसे परिवर्तित करूं ?

मैं एक longको बदलने की कोशिश कर रहा हूं byte[]ताकि मैं byte[]एक टीसीपी कनेक्शन भेज सकूं। दूसरी तरफ मैं byte[]इसे लेना चाहता हूं और इसे वापस एक में बदल देता हूं double


एक और विकल्प Maps.transformValues ​​होगा, जो संग्रह को परिवर्तित करने के लिए एक सामान्य टूलिंग है। docs.guava-lbooks.googlecode.com/git-history/release/javadoc/…
Raul

1
यदि आपका लक्ष्य एक लंबी संख्या के Base64 चार्ट में बदलना है, तो stackoverflow.com/q/27559449/32453 भी देखें ।
रोज़गारपैक

शायद इस बात पर जोर दिया जाना चाहिए कि रूपांतरण पाइपलाइन 'लंबी -> बाइट [] -> डबल' है, न कि 'लंबी -> बाइट [] -> लंबी -> डबल'।
किरील गमाज़कोव

जवाबों:


230
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();
}

या बाइटबर्फ बनाने से बचने के लिए एक कक्षा में लिपटे:

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();
    }
}

चूंकि यह इतना लोकप्रिय हो रहा है, मैं सिर्फ यह उल्लेख करना चाहता हूं कि मुझे लगता है कि आप अधिकांश मामलों में अमरूद जैसी लाइब्रेरी का उपयोग कर रहे हैं। और यदि आपके पास पुस्तकालयों के लिए कुछ अजीब विरोध है, तो आपको शायद देशी जावा समाधान के लिए पहले इस जवाब पर विचार करना चाहिए । मुझे लगता है कि मुख्य बात यह है कि मेरा जवाब वास्तव में इसके लिए है कि आपको सिस्टम के एंडियन-नेस के बारे में चिंता करने की आवश्यकता नहीं है।


3
चतुर ... लेकिन आप प्रत्येक रूपांतरण के लिए एक अस्थायी बाइटबफ़र बनाते हैं और त्यागते हैं। यदि आप प्रति संदेश और / या बहुत सारे संदेश भेज रहे हैं तो अच्छा नहीं है।
स्टीफन सी

1
@ स्टेफ़ेन - मैं केवल बाइटबफ़र का उपयोग करने के लिए प्रदर्शन करने के लिए पर्याप्त कर रहा था, लेकिन मैंने आगे बढ़कर एक उपयोगिता वर्ग में इसका उपयोग करने का एक उदाहरण जोड़ा।
ब्रैड मेस

8
मुझे लगता है कि यहां बाइट्स टोंगलॉन्ग () की स्थिति विफल हो जाएगी क्योंकि पुट बफर के अंत में है, शुरुआत नहीं। मुझे लगता है कि आपको एक बफर अंडरफ़्लो अपवाद मिलेगा।
एलेक्स मिलर

11
प्री-जावा 8, आप मैजिक नंबर से बचने के लिए Long.BYTES के बजाय Long.SIZE / Byte.SIZE का उपयोग कर सकते हैं।
jvdbogae

8
उस बाइटबफ़र का पुन: उपयोग अत्यधिक समस्याग्रस्त है, और न केवल थ्रेड-सुरक्षा कारणों के लिए जैसा कि अन्य ने टिप्पणी की थी। न केवल बीच में '.clear ()' की आवश्यकता होगी, लेकिन यह स्पष्ट नहीं है कि ByteBuffer पर कॉलिंग .ray () बैकिंग सरणी बनाम कॉपी में वापस आ रही है। इस प्रकार यदि आप बार-बार कॉल करते हैं और अन्य परिणामों पर पकड़ रखते हैं, तो वे वास्तव में सभी समान सरणी हैं जो बार-बार पिछले मानों को अधिलेखित कर रहे हैं। नीचे एक टिप्पणी में हडूप लिंक सबसे अधिक प्रदर्शन करने वाला है और इनमें से किसी भी मुद्दे से बचा जाता है।
एरोन ज़िनमैन


84

मैंने सादे बिटवाइज़ ऑपरेशन के खिलाफ बाइटबफ़र विधि का परीक्षण किया लेकिन बाद में काफी तेज है।

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;
}

1
परिणाम के बजाय | = (b [i] & 0xFF); हम केवल परिणाम का उपयोग कर सकते हैं। = b [i]; के रूप में और एक बिट के लिए 0xFF के साथ कुछ भी संशोधित नहीं है।
विपुल

3
@Vipul बिटवाइज़-और मायने रखता है क्योंकि जब केवल result |= b[i]बाइट वैल्यू करते हैं तो पहले इसे लंबे समय तक परिवर्तित किया जाएगा जो साइन एक्सटेंशन करता है। मूल्य -128 (हेक्स 0x80) के साथ एक बाइट मूल्य -128 (हेक्स ) के साथ एक लंबे समय में बदल जाएगा 0xFFFF FFFF FFFF FF80। रूपांतरण के बाद सबसे पहले मान या: ed एक साथ हैं। बिटवाइज़ का उपयोग करना और पहले से बाइट को एक इंट में बदलना और साइन एक्सटेंशन को काटकर इससे बचाव करना (byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80:। जावा में बाइट्स क्यों हस्ताक्षर किए जाते हैं यह मेरे लिए थोड़ा रहस्य है, लेकिन मुझे लगता है कि यह अन्य प्रकारों के साथ फिट है।
ब्रेनस्टॉर्म

@ ब्रेनस्टॉर्म मैंने केस -128 की कोशिश की। = b [i] और साथ | = = (b [i] & 0xFF) और परिणाम समान हैं !!
महमूद हनाफ़ी

समस्या यह है कि पारी को लागू करने से पहले बाइट को बढ़ावा दिया जाता है जो साइन बिट के साथ अजीब समस्याएं पैदा करता है। इसलिए हम पहली और (&) इसे 0xFF के साथ शिफ्ट करने के लिए सही मूल्य प्राप्त करने के लिए।
Wytze

मैं इस डेटा (डेटा = नई बाइट [] {(बाइट) 0xDB, (बाइट) 0xA7, 0x53, (बाइट) 0xF8, (बाइट) 0xA8, 0xC8, 0x66, 0x66, 0x8} () को लंबे समय तक बदलने की कोशिश करता हूं, लेकिन यह वापस लौटता है; गलत मान -2619032330856274424, अपेक्षित मान 989231983928329832
जेफ्री जैकी

29

यदि आप एक तेजी से अनियंत्रित संस्करण की तलाश कर रहे हैं, तो यह चाल करना चाहिए, बाइट सरणी को "बी" कहा जाता है, जिसकी लंबाई 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)};

1
धन्यवाद, सबसे अच्छा!
Miha_x64

15

आपको बाइट की आवश्यकता क्यों है []? सिर्फ सॉकेट के लिए क्यों नहीं लिखा?

मुझे लगता है तुम्हारा मतलब लंबे बजाय लांग , बाद की जरूरत है शून्य मान के लिए अनुमति देने के लिए।

DataOutputStream dos = new DataOutputStream(
     new BufferedOutputStream(socket.getOutputStream()));
dos.writeLong(longValue);

DataInputStream dis = new DataInputStream(
     new BufferedInputStream(socket.getInputStream()));
long longValue = dis.readLong();

8
उन्होंने पूछा कि आप बाइट [] और बैक में कैसे परिवर्तित होते हैं। अच्छा जवाब लेकिन सवाल का जवाब नहीं दिया। आप पूछते हैं कि क्यों आप मानते हैं कि यह अनावश्यक है लेकिन यह एक गलत धारणा है। अगर वह क्रॉस-लैंग्वेज या क्रॉस-प्लेटफॉर्म कर रहा है तो क्या होगा? DataOutputStream आपकी मदद नहीं करेगा।
user1132959

4
यदि वह क्रॉस-लैंग्वेज या क्रॉस-प्लेटफॉर्म कर रहा है, तो बाइट्स को एक ज्ञात क्रम में भेजना महत्वपूर्ण है। यह विधि डॉक्स के अनुसार ऐसा करती है (यह उन्हें "हाई बाइट फर्स्ट" लिखती है)। स्वीकृत उत्तर नहीं है (यह डॉक्स के अनुसार "वर्तमान क्रम" में उन्हें लिखता है)। प्रश्न में कहा गया है कि वह उन्हें टीसीपी कनेक्शन पर भेजना चाहता है। byte[]कि अंत करने के लिए सिर्फ एक साधन है।
इयान मैक्लेयर

3
@IanMcLaird स्वीकृत उत्तर ज्ञात आदेश का उपयोग करता है। यह एक नया बनाता है ByteBufferजो डॉक्स के अनुसार "बाइट बफर का प्रारंभिक क्रम हमेशा BIG_ENDIAN है।
डेविड फिलिप्स

4

बस एक अंतर्निहित ByteArrayOutputStream के साथ DataOutputStream में लंबा लिखें । ByteArrayOutputStream से आप byByteArray () के माध्यम से बाइट-सरणी प्राप्त कर सकते हैं :

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));       
        }
}

तदनुसार अन्य प्राइमेटिव के लिए काम करता है।

संकेत: टीसीपी के लिए आपको मैन्युअल रूप से बाइट [] की आवश्यकता नहीं है। आप सॉकेट socket और उसकी धाराओं का उपयोग करेंगे

OutputStream os=socket.getOutputStream(); 
DataOutputStream dos=new DataOutputStream(os);
dos.writeLong(l);
//etc ..

बजाय।


4

आप कार्यान्वयन का उपयोग org.apache.hadoop.hbase.util.Bytes http://hbase.apache.org/apidocs/org/apache/hadoop/hbase/util/Bytes.html में कर सकते हैं

स्रोत कोड यहाँ है:

http://grepcode.com/file/repository.cloudera.com/content/repositories/releases/com.cloudera.hbase/hbase/0.89.20100924-28/org/apache/hadoop/hbase/util/Bytes.java# Bytes.toBytes% 28long% 29

लोंग और बाइट्स तरीकों के लिए देखें।

मेरा मानना ​​है कि सॉफ़्टवेयर लाइसेंस आपको कोड के कुछ हिस्सों को लेने और इसका उपयोग करने की अनुमति देता है लेकिन कृपया इसे सत्यापित करें।


क्यों यह कार्यान्वयन OR के बजाय XOR (^ =) का उपयोग करता है? github.com/apache/hbase/blob/master/hbase-common/src/main/java/…
Vijtim

3
 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;
    }

2
आप ArrayList को छोड़ सकते हैं: सार्वजनिक स्थिर बाइट [] longToBytes (long l) {long num = l; बाइट [] बाइट्स = नई बाइट [8]; for (int i = bytes.length - 1, i> = 0; i--) {बाइट्स [i] = (बाइट) (संख्या & 0xff); संख्या >> = 8; } वापसी bytesp; }
eckes

मूल विधि नकारात्मक संख्याओं के साथ काम नहीं करती है क्योंकि यह एक अनंत लूप में मिलती है जबकि (l! = 0), @ eckes की विधि 127 से अधिक संख्याओं के साथ काम नहीं करती है क्योंकि वह 127 कारणों से नकारात्मक होने वाले बाइट्स के लिए खाता नहीं है। वे हस्ताक्षरित हैं।
Big_Bad_E

2

मैं एक और उत्तर जोड़ूंगा जो सबसे तेज एक संभव yes है (हाँ, स्वीकृत उत्तर से भी अधिक), लेकिन यह हर एक मामले के लिए काम नहीं करेगा। अब, यह हर कल्पनीय परिदृश्य के लिए काम करेगा:

आप बस स्ट्रिंग को मध्यवर्ती के रूप में उपयोग कर सकते हैं। ध्यान दें, यह आपको सही परिणाम देगा, भले ही ऐसा लगता है कि स्ट्रिंग का उपयोग करने से गलत परिणाम मिल सकते हैं, जैसा कि आप जानते हैं कि आप "सामान्य" स्ट्रिंग्स के साथ काम कर रहे हैं। यह प्रभावशीलता बढ़ाने और कोड को सरल बनाने के लिए एक विधि है जिसके बदले में इसके द्वारा संचालित डेटा स्ट्रिंग्स पर कुछ मान्यताओं का उपयोग करना चाहिए।

इस विधि का उपयोग करने का Con: यदि आप ASCII तालिका की शुरुआत में कुछ ASCII वर्णों के साथ इन प्रतीकों की तरह काम कर रहे हैं, तो निम्न पंक्तियाँ विफल हो सकती हैं, लेकिन चलो इसका सामना करते हैं - आप शायद वैसे भी कभी भी इनका उपयोग नहीं करेंगे।

इस विधि का उपयोग करने के प्रो: याद रखें कि अधिकांश लोग आमतौर पर बिना किसी असामान्य चरित्र के कुछ सामान्य तारों के साथ काम करते हैं और फिर विधि सबसे सरल और सबसे तेज़ तरीका है।

लंबे से बाइट तक []:

byte[] arr = String.valueOf(longVar).getBytes();

बाइट से [] तक:

long longVar = Long.valueOf(new String(byteArr)).longValue();

2
नेक्रोपोस्टिंग के लिए क्षमा करें, लेकिन यह सिर्फ गलत है। ई। जी। String.valueOf (0) .getBytes () [0] == 0x30। आश्चर्य! स्ट्रिंग # getBytes ASCII- एन्कोड किए गए अंकों के प्रतीकों को लौटाएगा, अंकों को नहीं: '0'! = 0, लेकिन '0' == 0x30
Kirill Gamazkov

अच्छा हो सकता है कि अगर आपने मेरा पूरा उत्तर पढ़ा हो, तो आपने देखा होगा कि मैंने इसके बारे में खुद ही जवाब दे दिया है ..
योनातन नीर

1
आह, मैं इस बिंदु से चूक गया कि मध्यवर्ती बाइट [] डेटा को (लगभग) अपारदर्शी के रूप में माना जाता है। इस परिदृश्य के लिए आपकी चाल चलेगी।
किरील गमाज़कोव

1

यदि आप 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 प्राप्त पक्ष पर।



0

यहाँ जावा 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));
}

परिवर्तित longकरने को दो-पूर्णांक मानों के उच्च और निम्न-क्रम बिट्स के रूप में व्यक्त किया जा सकता है जो एक बिटवाइज़-ओआर के अधीन हैं। ध्यान दें कि toUnsignedLongसे है Integerवर्ग और करने के लिए पहली कॉल toUnsignedLongज़रूरत से ज़्यादा हो सकता है।

विपरीत रूपांतरण को अनियंत्रित किया जा सकता है, जैसा कि दूसरों ने उल्लेख किया है।


0

लंबे और बाइट के लिए कोटलीन एक्सटेंशन प्रकार:

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 में पूरा कोड देख सकते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.