Javaでa long
をa に変換してbyte[]
戻す方法を教えてください。
TCP接続経由で送信できるようにa long
をaに変換しようとしています。反対側では、それを取得してに戻したいと思います。byte[]
byte[]
byte[]
double
Javaでa long
をa に変換してbyte[]
戻す方法を教えてください。
TCP接続経由で送信できるようにa long
をaに変換しようとしています。反対側では、それを取得してに戻したいと思います。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();
}
}
これは非常に人気が高まっているので、ほとんどの場合、Guavaのようなライブラリを使用したほうがいいと思います。ライブラリに奇妙な反対がある場合は、ネイティブ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(16進数0x80
)のバイトは、値が-128(16進数)のlongに変わり0xFFFF FFFF FFFF FF80
ます。最初に変換後の値は、or:edされます。bitwise-andを使用すると、最初にバイトをintに変換し、符号拡張を切り離すことでこれを防止します(byte)0x80 & 0xFF ==> (int)0xFFFF FF80 & 0xFF ==> (int) 0x80
。なぜバイトがJavaで署名されるのか私には少し不思議ですが、それは他の型に合わせる必要があると思います。
高速のアンロールバージョンを探している場合は、長さが8の「b」というバイト配列を想定して、これでうまくいくはずです。
byte []-> long
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)};
なぜbyte []が必要なのですか?なぜそれをソケットに書き込むのではないのですか?
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
ドキュメントに応じた「バイトバッファの初期順序は、常にBIG_ENDIANです。
基になるByteArrayOutputStreamでDataOutputStreamに longを書き込むだけです。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;
}
私は可能な限り最速の別の回答を追加しますye(はい、受け入れられた回答よりもさらに多いです)が、すべてのケースで機能するわけではありません。ただし、考えられるすべてのシナリオで機能します。
Stringを中間として使用できます。「通常」の文字列で作業していることを知っている限り、文字列を使用すると誤った結果が生じる可能性があるように見えても、これにより正しい結果が得られます。これは有効性を高め、コードをより単純にする方法であり、操作するデータ文字列に対していくつかの仮定を使用する必要があります。
この方法の欠点:場合の欠点 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の対象となる2つの整数値の上位ビットと下位ビットとして表すことができます。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で完全なコードを見ることができます