byte (字节) 是 Java 中的基本数据类型,一个 byte 包含8个 bit(位),byte 的取值范围是-128到+127。
byte 跟 Java 其他基本类型的关系:
基本类型 | 所占字节数 | 备注 |
---|---|---|
byte | 1 | |
short | 2 | |
int | 4 | |
long | 8 | |
char | 2 | |
float | 4 | |
double | 8 | |
boolean | 1、4 | 《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来 |
由于工作关系,我封装了一个操作字节的库
github 地址: github.com/fengzhizi71…
Bytes 是一个接口,它有三个实现类:ByteArrayBytes、ByteBufferBytes、MmapBytes。其中,前面两个实现类是 Immutable 对象。
Immutable 对象(不可变对象),即对象一旦被创建它的状态(对象的数据,也即对象属性值)就不能改变。
它的优点:
对 Bytes 中的 byte[] 进行加密。在 Bytes 接口中,包含下面的默认函数:
/** * 使用md5加密 * @return */ default Bytes md5() { return transform(new MessageDigestTransformer("MD5")); } /** * 使用sha1加密 * @return */ default Bytes sha1() { return transform(new MessageDigestTransformer("SHA-1")); } /** * 使用sha256加密 * @return */ default Bytes sha256() { return transform(new MessageDigestTransformer("SHA-256")); } 复制代码
进行单元测试:
@Test public void testHash() { Bytes bytes = ByteArrayBytes.create("hello world"); assertEquals("5eb63bbbe01eeed093cb22bb8f5acdc3", bytes.md5().toHexString()); assertEquals("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", bytes.sha1().toHexString()); assertEquals("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", bytes.sha256().toHexString()); } 复制代码
支持对象的序列化、反序列化以及深拷贝。在 Bytes 接口中,包含下面的静态函数:
/** * 序列化对象,转换成字节数组 * @param obj * @return */ static byte[] serialize(Object obj) { byte[] result = null; ByteArrayOutputStream fos = null; try { fos = new ByteArrayOutputStream(); ObjectOutputStream o = new ObjectOutputStream(fos); o.writeObject(obj); result = fos.toByteArray(); } catch (IOException e) { System.err.println(e); } finally { IOUtils.closeQuietly(fos); } return result; } /** * 反序列化字节数字,转换成对象 * @param bytes * @return */ static Object deserialize(byte[] bytes) { InputStream fis = null; try { fis = new ByteArrayInputStream(bytes); ObjectInputStream o = new ObjectInputStream(fis); return o.readObject(); } catch (IOException e) { System.err.println(e); } catch (ClassNotFoundException e) { System.err.println(e); } finally { IOUtils.closeQuietly(fis); } return null; } /** * 通过序列化/反序列化实现对象的深拷贝 * @param obj * @param <T> * @return */ static <T> T cloneObject(T obj) { return (T) deserialize(serialize(obj)); } 复制代码
进行单元测试:
@Test public void testSerializeAndDeserialize() { User u = new User(); u.name = "tony"; u.password = "123456"; byte[] bytes = Bytes.serialize(u); User newUser = (User)Bytes.deserialize(bytes); assertEquals(u.name, newUser.name); assertEquals(u.password,newUser.password); } @Test public void testDeepCopy() { User u = new User(); u.name = "tony"; u.password = "123456"; User newUser = Bytes.cloneObject(u); System.out.println(u); System.out.println(newUser); assertNotSame(u,newUser); assertNotSame(u.name,newUser.name); } 复制代码
testDeepCopy() 执行后,u 和 newUser 地址的不同,u.name 和newUser.name 指向的内存地址也不同。
com.safframework.bytekit.domain.User@2b05039f com.safframework.bytekit.domain.User@17d10166 复制代码
copy、contact、reverse 都是采用 Transformer 的方式。在 AbstractBytes 类中,包含下面的函数:
@Override public Bytes copy() { return transform(new CopyTransformer(0, size())); } @Override public Bytes copy(int offset, int length) { return transform(new CopyTransformer(offset, length)); } @Override public Bytes contact(byte[] bytes) { return transform(new ConcatTransformer(bytes)); } @Override public Bytes reverse() { return transform(new ReverseTransformer()); } 复制代码
进行单元测试:
@Test public void testContact() { Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes()); assertEquals(bytes.toString(), "hello world tony"); } @Test public void testCopy() { Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes()); assertEquals(bytes.toString(), bytes.copy().toString()); } @Test public void testReverse() { Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes()); assertEquals(bytes.toString(), bytes.reverse().reverse().toString()); } 复制代码
xor、and、or、not 也是采用 Transformer 的方式。在 AbstractBytes 类中,包含下面的函数:
@Override public Bytes xor(byte[] bytes) { return transform(new BitWiseOperatorTransformer(bytes,BitWiseOperatorTransformer.Mode.XOR)); } @Override public Bytes and(byte[] bytes) { return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.AND)); } @Override public Bytes or(byte[] bytes) { return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.OR)); } @Override public Bytes not(byte[] bytes) { return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.NOT)); } 复制代码
进行单元测试:
@Test public void testBitWise() { ByteBufferBytes bytes = (ByteBufferBytes)ByteBufferBytes.create("hello world").contact(" tony".getBytes()); assertEquals(bytes.toString(), bytes.and(bytes.toByteArray()).or(bytes.toByteArray()).toString()); assertEquals(bytes.toString(), bytes.not(bytes.toByteArray()).not(bytes.toByteArray()).toString()); assertEquals(bytes.toString(), bytes.xor(bytes.toByteArray()).xor(bytes.toByteArray()).toString()); //两次xor 返回本身 } 复制代码
@Test public void testBase64() { ByteBufferBytes bytes = (ByteBufferBytes)ByteBufferBytes.create("hello world").contact(" tony".getBytes()); String base64 = new String(bytes.encodeBase64()); assertEquals(bytes.toString(), new String(Bytes.parseBase64(base64))); } 复制代码
@Test public void testToByteArray() { Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes()); assertEquals(bytes.toString(), new String(bytes.toByteArray())); } 复制代码
Linux 的 mmap 是一种内存映射文件的方法。
mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。mmap在用户空间映射调用系统中作用很大。 mmap系统调用是将一个打开的文件映射到进程的用户空间,mmap系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read()、write()等操作。
import com.safframework.bytekit.domain.User; import com.safframework.bytekit.jdk.mmap.MmapBytes; import org.junit.After; import org.junit.Before; import org.junit.Test; import static junit.framework.TestCase.assertEquals; /** * Created by tony on 2018-12-24. */ public class MmapBytesTest { private MmapBytes mmapBytes; private String file; @Before public void setUp() { file = "test"; mmapBytes = new MmapBytes(file, (long) 1024 * 10); // 10M } @Test public void testWriteAndRead() throws Exception { mmapBytes.writeInt(12); mmapBytes.writeInt(34); mmapBytes.writeByte((byte) 5); mmapBytes.writeBytes(("this is tony").getBytes()); mmapBytes.writeLong(6666L); mmapBytes.writeDouble(3.14d); assertEquals(12, mmapBytes.readInt()); assertEquals(34, mmapBytes.readInt()); assertEquals((byte) 5, mmapBytes.readByte()); assertEquals("this is tony", new String(mmapBytes.readBytes(12))); assertEquals(6666L, mmapBytes.readLong()); assertEquals(3.14d, mmapBytes.readDouble()); } @Test public void testObject() throws Exception { User u = new User(); u.name = "tony"; u.password = "123456"; mmapBytes.writeObject(u); User temp = (User)mmapBytes.readObject(117); assertEquals(u.name, temp.name); assertEquals(u.password, temp.password); } @Test public void testFree() throws Exception { mmapBytes.writeInt(12); mmapBytes.writeInt(34); mmapBytes.writeByte((byte) 5); mmapBytes.free(); mmapBytes = new MmapBytes(file, (long) 1024 * 10); // 10M mmapBytes.writeInt(67); assertEquals(67, mmapBytes.readInt()); } @After public void tearDown() { mmapBytes.free(); } } 复制代码
bytekit 是一个操作字节的工具库,不依赖任何第三方库。它封装了字节数组、ByteBuffer 的操作,支持 mmap 常用的读写。
当然,它还可以封装 protobuf 的 ByteString 或者 Android 中的 Parcel,只需实现 Bytes 接口即可。
参考资料: