com.jd.blockchain.utils.io.ByteArray Maven / Gradle / Ivy
The newest version!
package com.jd.blockchain.utils.io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import org.springframework.util.Base64Utils;
import com.jd.blockchain.utils.ByteSequence;
import com.jd.blockchain.utils.codec.Base58Utils;
import com.jd.blockchain.utils.codec.HexUtils;
/**
* ByteArray 二进制字节块是对字节数组的包装,目的是提供一种不可变的二进制数据结构;
*
* @author huanghaiquan
*
*/
public class ByteArray implements Externalizable, ByteSequence {
public static final ByteArray EMPTY = ByteArray.wrap(new byte[0]);
private byte[] bytes;
private int hashCode;
private ByteArray readonlyWrapper = null;
private ByteArray(byte[] bytes) {
this(bytes, false);
}
private ByteArray(byte[] bytes, boolean readonly) {
this.bytes = bytes;
this.hashCode = Arrays.hashCode(bytes);
// this.readonly = readonly;
}
public int size() {
return bytes.length;
}
public byte get(int i) {
return bytes[i];
}
// public boolean isReadonly() {
// return readonly;
// }
public void copy(int srcPos, byte[] dest, int destPos, int length) {
System.arraycopy(bytes, srcPos, dest, destPos, length);
}
public ByteArray() {}
@Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof ByteArray)) {
return false;
}
ByteArray target = (ByteArray) obj;
if (this.bytes == target.bytes) {
return true;
}
return BytesUtils.equals(target.bytes, this.bytes);
}
@Override
public int hashCode() {
return Arrays.hashCode(bytes);
}
/**
* 对指定的字节数组的副本进行包装;
*
* @param bytes bytes
* @return ByteArray
*/
public static ByteArray wrapCopy(byte[] bytes) {
byte[] replica = Arrays.copyOf(bytes, bytes.length);
return new ByteArray(replica);
}
/**
* 对指定的字节数组直接进行包装;
*
* @param bytes bytes
* @return ByteArray
*/
public static ByteArray wrap(byte[] bytes) {
return new ByteArray(bytes);
}
/**
* 对指定的字节数组直接进行包装;
*
* @param oneByte oneByte
* @return ByteArray
*/
public static ByteArray wrap(byte oneByte) {
return new ByteArray(new byte[] { oneByte });
}
/**
* 对指定的字节数组的副本进行包装;
*
* @param bytes bytes
* @return ByteArray
*/
public static ByteArray wrapCopyReadonly(byte[] bytes) {
byte[] replica = Arrays.copyOf(bytes, bytes.length);
return new ByteArray(replica, true);
}
/**
* 对指定的字节数组直接进行包装;
*
* @param bytes bytes
* @return ByteArray
*/
public static ByteArray wrapReadonly(byte[] bytes) {
return new ByteArray(bytes, true);
}
/**
* 对指定的字节数组直接进行包装;
*
* @param oneByte oneByte
* @return ByteArray
*/
public static ByteArray wrapReadonly(byte oneByte) {
return new ByteArray(new byte[] { oneByte }, true);
}
/**
* 将字节内容完整写入指定的输出流;
* @param out out
* @return int
*/
public int writeTo(OutputStream out) {
try {
out.write(bytes);
return bytes.length;
} catch (IOException e) {
throw new RuntimeIOException(e.getMessage(), e);
}
}
public InputStream asInputStream() {
return new ByteArrayInputStream(bytes);
}
public ByteBuffer asReadOnlyBuffer() {
return ByteBuffer.wrap(bytes).asReadOnlyBuffer();
}
// public ByteArray asReadonly() {
// if (readonly) {
// return this;
// }
// if (readonlyWrapper == null) {
// readonlyWrapper = new ByteArray(bytes, true);
// }
// return readonlyWrapper;
// }
/**
* 返回原始的二进制数组的副本;
*
* 注:使用者要注意此操作代理的内存性能的影响;
*
* @return byte array;
*/
public byte[] bytesCopy() {
return Arrays.copyOf(bytes, bytes.length);
}
@Override
public int copyTo(int sourceOffset, byte[] dest, int destOffset, int length) {
System.arraycopy(bytes, sourceOffset, dest, destOffset, length);
return length;
}
/**
* 返回原始的字节数组;
*
*
* 如果字节数组被标识为只读,调用此方法将引发异常 IllegalStateException;
*
* 注:应谨慎操作此方法返回的字节数组,通常的原则是不应更改返回的字节数组,用于只读的情形;
*
* @return byte array;
*/
public byte[] bytes() {
// if (readonly) {
// throw new IllegalStateException("This byte array is readonly!");
// }
return bytes;
}
public String toHex() {
return toHex(bytes);
}
public String toBase64() {
return toBase64(bytes);
}
public String toBase58() {
return toBase58(bytes);
}
/**
* 返回 ByteArray 的 Base58 字符;
*/
@Override
public String toString() {
return toBase58();
}
public static ByteArray parseHex(String hexString) {
return wrap(fromHex(hexString));
}
public static ByteArray parseBase58(String base58String) {
return wrap(fromBase58(base58String));
}
public static ByteArray parseBase64(String base64String) {
return wrap(fromBase64(base64String));
}
public static ByteArray parseString(String str, String charset) {
return wrap(fromString(str, charset));
}
public static String toHex(byte[] bytes) {
return HexUtils.encode(bytes);
}
public static String toBase58(byte[] bytes) {
return Base58Utils.encode(bytes);
}
public static String toBase64(byte[] bytes) {
return Base64Utils.encodeToUrlSafeString(bytes);
}
public String toString(String charset) {
return BytesUtils.toString(bytes, charset);
}
public static byte[] fromHex(String hexString) {
return HexUtils.decode(hexString);
}
public static byte[] fromBase58(String base58String) {
return Base58Utils.decode(base58String);
}
public static byte[] fromBase64(String base64String) {
return Base64Utils.decodeFromUrlSafeString(base64String);
}
public static byte[] fromString(String str, String charset) {
return BytesUtils.toBytes(str, charset);
}
/**
* The object implements the writeExternal method to save its contents
* by calling the methods of DataOutput for its primitive values or
* calling the writeObject method of ObjectOutput for objects, strings,
* and arrays.
*
* @param out the stream to write the object to
* @throws IOException Includes any I/O exceptions that may occur
* @serialData Overriding methods should use this tag to describe
* the data layout of this Externalizable object.
* List the sequence of element types and, if possible,
* relate the element to a public/protected field and/or
* method of this Externalizable class.
*/
@Override
public void writeExternal(ObjectOutput out) throws IOException {
ByteArrayOutputStream os = new ByteArrayOutputStream();
writeTo(os);
byte[] bts = os.toByteArray();
out.writeInt(bts.length);
out.write(bts);
}
/**
* The object implements the readExternal method to restore its
* contents by calling the methods of DataInput for primitive
* types and readObject for objects, strings and arrays. The
* readExternal method must read the values in the same sequence
* and with the same types as were written by writeExternal.
*
* @param in the stream to read data from in order to restore the object
* @throws IOException if I/O errors occur
* @throws ClassNotFoundException If the class for an object being
* restored cannot be found.
*/
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
int len = in.readInt();
byte[] bts = new byte[len];
in.readFully(bts);
this.bytes = bts;
}
@Override
public byte byteAt(int index) {
return bytes[index];
}
@Override
public ByteSequence subSequence(int start, int end) {
return new BytesSlice(bytes, start, end - start);
}
}