চরকে [] বাইটে রূপান্তর করা []


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

সমাধানটি পাসে পাসওয়ার্ডগুলি সংরক্ষণ করার জন্য সুইংয়ের প্রস্তাবনা থেকে অনুপ্রাণিত হয় []। (দেখুন পাসওয়ার্ডগুলির জন্য স্ট্রিংয়ের চেয়ে চর [] কেন পছন্দ করা হয়? )

লগগুলিতে সংবেদনশীল ডেটা না লিখে এবং জেভিএম এতে কোনও রেফারেন্স রাখবে না তা নিশ্চিত করুন।


উপরের কোডটি সঠিক তবে কার্যকর নয়। আপনার যদি পারফরম্যান্সের প্রয়োজন না হয় তবে সুরক্ষা চান তবে আপনি এটি ব্যবহার করতে পারেন। যদি সুরক্ষাও লক্ষ্য না হয় তবে সহজভাবে করুন String.getBytes। আপনি encodeযদি জেডিকে বাস্তবায়নের বিষয়টি নীচে দেখেন তবে উপরের কোড কার্যকর নয় । এছাড়াও আপনাকে অ্যারে অনুলিপি করতে এবং বাফার তৈরি করতে হবে। রূপান্তর করার আরেকটি উপায় হ'ল পিছনের সমস্ত কোডের ইনলাইন encode(উদাহরণস্বরূপ ইউটিএফ -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"))

স্কাল ভাষা ব্যবহারের জন্য আমাকে ক্ষমা করুন। এই কোডটি জাভাতে রূপান্তর করতে আপনার যদি সমস্যা হয় তবে আমি এটি আবার লিখতে পারি। কর্মক্ষমতা সম্পর্কে কী সবসময় আসল ডেটা পরীক্ষা করুন (উদাহরণস্বরূপ জেএমএইচ সহ)। এই কোডটি আপনি জেডিকে [ ] এবং প্রোটোবুফ [ 3 ] এ দেখতে পাচ্ছেন এমন কিছুর সাথে একই রকম দেখাচ্ছে ।


এটি কি বাইটবফার তৈরি করবে না? আমার ধারণা, স্ট্রিং অবজেক্টের চেয়ে দাম কম?
অ্যান্ডি জে

15
@ ক্রেজিজে আমি বিশ্বাস করি যে এই পদ্ধতিটি স্ট্রিংপুলে "চর" সংরক্ষণ করবে না। এই ভাবে আপনি আরও সুরক্ষিত পাসওয়ার্ড ডেটা নিয়ে কাজ করতে পারেন।
Andrii Nemchenko

4
@ ক্যাসিয়ান আপনার পদ্ধতিটি ভুলভাবে কাজ করে। বিশদটি এখানে পড়ুন stackoverflow.com/a/20604909/355491
Andrii Nemchenko

4
@ প্রাপস নং, একটি ইউটিএফ -8 অক্ষর 1 থেকে 4 বাইট পর্যন্ত লাগে। এমনকি একটি ASCII চরিত্র 8 বিট লাগে।
আন্দ্রেই নেমচেঙ্কো

4
এই 'টুবাইটস ()' পদ্ধতির একটি গুরুত্বপূর্ণ পার্শ্ব প্রতিক্রিয়া রয়েছে। এটি ইনপুট চরগুলি মুছে দেয়। charBuffer.array () আসলে ইনপুট অক্ষর। অ্যারে.ফিল () আসলে ইনপুটটি মুছবে। অনেক ক্ষেত্রে এটি ঠিক আছে তবে কিছু সময় এটি অনাকাঙ্ক্ষিত প্রভাব তৈরি করে।
গুয়াংল্যাং

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

পিছনে \ 0 বাস্তবায়ন নির্দিষ্ট হতে পারে? আমি নেটবিন .4.৪ সহ ১.7_51 ব্যবহার করছি এবং কোনও পিছনে \ 0 লক্ষ্য করছি না।

@ orthopteroid হ্যাঁ এই উদাহরণটি jvm নির্দিষ্ট হতে পারে। এটি ওরাকল 1.7.0_45 লিনাক্স 64 বিট (স্মৃতি থেকে) দিয়ে চালানো হয়েছিল। নিম্নলিখিত প্রয়োগের সাথে ( গ্রেপকোড.ফায়াল / রিপোসিটরি.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

@ ডিজেসুথো আজ, আমার প্ল্যাটফর্মটি উইন্ডোজ 7 এক্স 64। দুঃখিত, কোডটি প্রদর্শন করতে পারছি না - আমি "System.arraycopy (str.getBytes (" UTF-8 "), 0, stor, 0, ব্যবহৃত) এর মতো কোড ব্যবহার করছি;" এখন

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 এ 'নিখুঁত ন্যূনতম প্রতিটি সফ্টওয়্যার বিকাশকারী অবশ্যই, ইউনিকোড এবং চরিত্রের সেটগুলি সম্পর্কে কোনও ধরণের প্রয়োজন নেই (অবশ্যই কোনও বাহানা নেই!)' পড়ুন
Ilane
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.