धर्मान्तरित चार [] बाइट के लिए []


84

मैं जावा में एक चरित्र सरणी को बाइट सरणी में बदलना चाहूंगा। इस रूपांतरण को बनाने के लिए क्या तरीके मौजूद हैं?

जवाबों:


76
char[] ch = ?
new String(ch).getBytes();

या

new String(ch).getBytes("UTF-8");

गैर-डिफ़ॉल्ट चार्ट प्राप्त करने के लिए।

अद्यतन: जावा 7 के बाद से:new String(ch).getBytes(StandardCharsets.UTF_8);


4
अधिकांश समय (वेब ​​ऐप्स) प्लेटफ़ॉर्म के डिफ़ॉल्ट चारसेट का उपयोग करना गलत है।
मातरिनस

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

167

Stringऑब्जेक्ट बनाए बिना कनवर्ट करें :

import java.nio.CharBuffer;
import java.nio.ByteBuffer;
import java.util.Arrays;

byte[] toBytes(char[] chars) {
  CharBuffer charBuffer = CharBuffer.wrap(chars);
  ByteBuffer byteBuffer = Charset.forName("UTF-8").encode(charBuffer);
  byte[] bytes = Arrays.copyOfRange(byteBuffer.array(),
            byteBuffer.position(), byteBuffer.limit());
  Arrays.fill(byteBuffer.array(), (byte) 0); // clear sensitive data
  return bytes;
}

उपयोग:

char[] chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
byte[] bytes = toBytes(chars);
/* do something with chars/bytes */
Arrays.fill(chars, '\u0000'); // clear sensitive data
Arrays.fill(bytes, (byte) 0); // clear sensitive data

समाधान झूले में [] में पासवर्ड स्टोर करने की सिफारिश से प्रेरित है। (देखें क्यों char [] पासवर्ड के लिए स्ट्रिंग पर पसंद किया गया है? )

याद रखें कि लॉग करने के लिए संवेदनशील डेटा न लिखें और यह सुनिश्चित करें कि जेवीएम इसका कोई संदर्भ नहीं रखेगा।


उपरोक्त कोड सही है लेकिन प्रभावी नहीं है। यदि आपको प्रदर्शन की आवश्यकता नहीं है, लेकिन सुरक्षा चाहते हैं तो आप इसका उपयोग कर सकते हैं। अगर सुरक्षा भी एक लक्ष्य नहीं है, तो बस करो String.getBytes। यदि आप encodeJDK के कार्यान्वयन को देखते हैं तो उपरोक्त कोड प्रभावी नहीं है । इसके अलावा आपको सरणियों की प्रतिलिपि बनाने और बफ़र्स बनाने की आवश्यकता है। कन्वर्ट करने का दूसरा तरीका सभी कोड को पीछे छोड़ना हैencode (उदाहरण के लिए UTF-8 ):

val xs: Array[Char] = "A ß € 嗨 𝄞 🙂".toArray
val len = xs.length
val ys: Array[Byte] = new Array(3 * len) // worst case
var i = 0; var j = 0 // i for chars; j for bytes
while (i < len) { // fill ys with bytes
  val c = xs(i)
  if (c < 0x80) {
    ys(j) = c.toByte
    i = i + 1
    j = j + 1
  } else if (c < 0x800) {
    ys(j) = (0xc0 | (c >> 6)).toByte
    ys(j + 1) = (0x80 | (c & 0x3f)).toByte
    i = i + 1
    j = j + 2
  } else if (Character.isHighSurrogate(c)) {
    if (len - i < 2) throw new Exception("overflow")
    val d = xs(i + 1)
    val uc: Int = 
      if (Character.isLowSurrogate(d)) {
        Character.toCodePoint(c, d)
      } else {
        throw new Exception("malformed")
      }
    ys(j) = (0xf0 | ((uc >> 18))).toByte
    ys(j + 1) = (0x80 | ((uc >> 12) & 0x3f)).toByte
    ys(j + 2) = (0x80 | ((uc >>  6) & 0x3f)).toByte
    ys(j + 3) = (0x80 | (uc & 0x3f)).toByte
    i = i + 2 // 2 chars
    j = j + 4
  } else if (Character.isLowSurrogate(c)) {
    throw new Exception("malformed")
  } else {
    ys(j) = (0xe0 | (c >> 12)).toByte
    ys(j + 1) = (0x80 | ((c >> 6) & 0x3f)).toByte
    ys(j + 2) = (0x80 | (c & 0x3f)).toByte
    i = i + 1
    j = j + 3
  }
}
// check
println(new String(ys, 0, j, "UTF-8"))

स्कैला भाषा का उपयोग करने के लिए मुझे क्षमा करें। यदि आपको इस कोड को जावा में परिवर्तित करने में समस्या है तो मैं इसे फिर से लिख सकता हूं। प्रदर्शन के बारे में हमेशा वास्तविक डेटा (उदाहरण के लिए जेएमएच के साथ) की जांच करें। यह कोड बहुत कुछ वैसा ही दिखता है जैसा आप JDK [ 2 ] और प्रोटोबॉफ़ [ 3 ] में देख सकते हैं ।


क्या यह बाइटबफ़र नहीं बनाएगा? मुझे लगता है कि एक स्ट्रिंग वस्तु की तुलना में कम महंगा है?
एंडी जे

15
@CrazyJay मुझे विश्वास है कि यह विधि स्ट्रिंग पूल में "वर्ण" को संग्रहीत नहीं करेगी। इस तरह आप पासवर्ड डेटा के साथ अधिक सुरक्षित काम कर सकते हैं।
एंड्री नेमचेंको जूल

1
@ कसियन आपका तरीका गलत तरीके से काम करता है। यहाँ विवरण पढ़ें stackoverflow.com/a/20604909/355491
एंड्री नेमचेंको

1
@Prabs नहीं, 1 से 4 बाइट्स से एक UTF-8 वर्ण लेता है। यहां तक ​​कि एक ASCII वर्ण 8 बिट्स लेता है।
एंड्री नेमचेंको

1
इस 'toBytes ()' विधि का एक महत्वपूर्ण दुष्प्रभाव है। यह इनपुट वर्णों को मिटा देता है। charBuffer.array () वास्तव में इनपुट वर्ण है। Arrays.fill () वास्तव में इनपुट मिटा देगा। कई मामलों में यह ठीक है, लेकिन कभी-कभी यह अवांछित प्रभाव पैदा करता है।
Guangliang

19

संपादित करें: एंड्री के उत्तर को अपडेट किया गया है ताकि निम्नलिखित अब लागू न हो।

एंड्री का जवाब (लेखन के समय सबसे अधिक मतदान) थोड़ा गलत है। मैंने इसे टिप्पणी के रूप में जोड़ा होगा लेकिन मैं बहुत सम्मानित नहीं हूं।

एंड्री के जवाब में:

char[] chars = {'c', 'h', 'a', 'r', 's'}
byte[] bytes = Charset.forName("UTF-8").encode(CharBuffer.wrap(chars)).array();

सरणी के लिए कॉल () वांछित मान नहीं लौटा सकता है, उदाहरण के लिए:

char[] c = "aaaaaaaaaa".toCharArray();
System.out.println(Arrays.toString(Charset.forName("UTF-8").encode(CharBuffer.wrap(c)).array()));

उत्पादन:

[97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0]

जैसा कि देखा जा सकता है कि एक शून्य बाइट जोड़ा गया है। इसके उपयोग से बचने के लिए निम्नलिखित हैं:

char[] c = "aaaaaaaaaa".toCharArray();
ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c));
byte[] b = new byte[bb.remaining()];
bb.get(b);
System.out.println(Arrays.toString(b));

उत्पादन:

[97, 97, 97, 97, 97, 97, 97, 97, 97, 97]

जैसा कि उत्तर भी पासवर्ड का उपयोग करने के लिए कहा जाता है, यह उस सरणी को खाली करने के लायक हो सकता है जो बाइटबफ़र (सरणी () फ़ंक्शन के माध्यम से एक्सेस) का समर्थन करता है:

ByteBuffer bb = Charset.forName("UTF-8").encode(CharBuffer.wrap(c));
byte[] b = new byte[bb.remaining()];
bb.get(b);
blankOutByteArray(bb.array());
System.out.println(Arrays.toString(b));

क्या अनुगामी \ _ कार्यान्वयन विशिष्ट हो सकता है? मैं netbeans 7.4 के साथ 1.7_51 का उपयोग कर रहा हूं और किसी भी ट्रेलिंग \ 0 को नहीं देख रहा हूं।

@orthopteroid हाँ यह उदाहरण विशिष्ट jvm हो सकता है। यह oracle 1.7.0_45 linux 64 बिट (मेमोरी से) के साथ चलाया गया था। निम्नलिखित कार्यान्वयन ( grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/… ) के साथ यदि आपको averageBytesPerChar()1 के अलावा कुछ भी मिलता है, तो आपको त्रुटियां मिलेंगी (मुझे 1.1 मिलेंगी)। ब्याज से बाहर ओएस / आर्च क्या आप उपयोग कर रहे हैं जैसा कि मैंने डबल के साथ 1.7.0_51 और ओपनजेक 1.7.0_51 के साथ जांच की और पाया कि यह 10 वर्णों से टूटा हुआ है।
djsutho

@ और कोई चिंता नहीं। ध्यान दें कि buffer.array()में toBytesसमारोह अभी भी अधिरोहित जा करने की जरूरत है, वर्तमान में केवल प्रति है।
djsutho

@ और मैंने परिवर्तनों को प्रतिबिंबित करने के लिए अपना उत्तर संपादित किया है।
djsutho

@djsutho आज, मेरा मंच windows7x64 है। क्षमा करें, कोड नहीं दिखा सकता - मैं "System.arraycopy (str.getBytes (" UTF-8 "), 0, stor, 0, used) जैसे कोड का उपयोग कर रहा हूं;" अभी।

0
private static byte[] charArrayToByteArray(char[] c_array) {
        byte[] b_array = new byte[c_array.length];
        for(int i= 0; i < c_array.length; i++) {
            b_array[i] = (byte)(0xFF & (int)c_array[i]);
        }
        return b_array;
}

-5

आप एक विधि बना सकते हैं:

public byte[] toBytes(char[] data) {
byte[] toRet = new byte[data.length];
for(int i = 0; i < toRet.length; i++) {
toRet[i] = (byte) data[i];
}
return toRet;
}

उम्मीद है की यह मदद करेगा


4
यह उत्तर गलत है क्योंकि चार्ट डेटा यूनिकोड है और इस तरह प्रति वर्ण 4 बाइट्स तक हो सकता है (अधिक संभव है, लेकिन वास्तविक जीवन में, मैं केवल 4 तक पाया गया हूं)। बस प्रत्येक चरित्र से एक बाइट लेना केवल बहुत सीमित चरित्र सेट के लिए काम करेगा। कृपया joelonsoftware.com/articles/Unicode.html पर यूनिकोड और कैरेक्टर सेट्स (नो एक्सक्यूज!) के बारे में 'द एब्सोल्यूट मिनिमम हर सॉफ्टवेयर डेवलपर' बिल्कुल पढ़ें, सकारात्मक रूप से अवश्य जान लें
इलयन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.