
一. Java 的字节
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 地址:https://github.com/fengzhizi715/bytekit
2.1 bytekit 的特点:
支持多种方式创建 Bytes
支持字节数组、ByteBuffer 的操作
支持 Immutable 对象:ByteArrayBytes、ByteBufferBytes
支持 Transformer: 内置 copy、contact、reverse、xor、and、or、not,也支持自定义 Transformer
支持 Hash: 内置 md5、sha1、sha256
支持转换成16进制字符串
支持 mmap 常用读写操作:readByte/writeByte、readBytes/writeBytes、readInt/writeInt、readLong/writeLong、readDouble/writeDouble、readObject/writeObject
支持对象的序列化、反序列化、深拷贝
不依赖任何第三方库

Bytes 是一个接口,它有三个实现类:ByteArrayBytes、ByteBufferBytes、MmapBytes。其中,前面两个实现类是 Immutable 对象。
2.2 支持 Immutable 对象
Immutable 对象(不可变对象),即对象一旦被创建它的状态(对象的数据,也即对象属性值)就不能改变。
它的优点:
构造、测试和使用都很简单
线程安全
当用作类的属性时不需要保护性拷贝
可以很好的用作Map键值和Set元素
2.3 支持 Hash 加密
对 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"));}
进行单元测试:
@Testpublic void testHash() {Bytes bytes = ByteArrayBytes.create("hello world");assertEquals("5eb63bbbe01eeed093cb22bb8f5acdc3", bytes.md5().toHexString());assertEquals("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", bytes.sha1().toHexString());assertEquals("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9", bytes.sha256().toHexString());}
2.4 序列化、反序列化、深拷贝
支持对象的序列化、反序列化以及深拷贝。在 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));}
进行单元测试:
@Testpublic 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);}@Testpublic 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@2b05039fcom.safframework.bytekit.domain.User@17d10166
2.5 copy、contact、reverse
copy、contact、reverse 都是采用 Transformer 的方式。在 AbstractBytes 类中,包含下面的函数:
@Overridepublic Bytes copy() {return transform(new CopyTransformer(0, size()));}@Overridepublic Bytes copy(int offset, int length) {return transform(new CopyTransformer(offset, length));}@Overridepublic Bytes contact(byte[] bytes) {return transform(new ConcatTransformer(bytes));}@Overridepublic Bytes reverse() {return transform(new ReverseTransformer());}
进行单元测试:
@Testpublic void testContact() {Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());assertEquals(bytes.toString(), "hello world tony");}@Testpublic void testCopy() {Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());assertEquals(bytes.toString(), bytes.copy().toString());}@Testpublic void testReverse() {Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());assertEquals(bytes.toString(), bytes.reverse().reverse().toString());}
2.6 位操作
xor、and、or、not 也是采用 Transformer 的方式。在 AbstractBytes 类中,包含下面的函数:
@Overridepublic Bytes xor(byte[] bytes) {return transform(new BitWiseOperatorTransformer(bytes,BitWiseOperatorTransformer.Mode.XOR));}@Overridepublic Bytes and(byte[] bytes) {return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.AND));}@Overridepublic Bytes or(byte[] bytes) {return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.OR));}@Overridepublic Bytes not(byte[] bytes) {return transform(new BitWiseOperatorTransformer(bytes, BitWiseOperatorTransformer.Mode.NOT));}
进行单元测试:
@Testpublic 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 返回本身}
2.7 Base64 编码、解码
@Testpublic 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)));}
2.8 Bytes 转换成字节数组
@Testpublic void testToByteArray() {Bytes bytes = ByteBufferBytes.create("hello world").contact(" tony".getBytes());assertEquals(bytes.toString(), new String(bytes.toByteArray()));}
三. mmap 的操作
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;@Beforepublic void setUp() {file = "test";mmapBytes = new MmapBytes(file, (long) 1024 * 10); // 10M}@Testpublic 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());}@Testpublic 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);}@Testpublic void testFree() throws Exception {mmapBytes.writeInt(12);mmapBytes.writeInt(34);mmapBytes.writeByte((byte) 5);mmapBytes.free();mmapBytes = new MmapBytes(file, (long) 1024 * 10); // 10MmmapBytes.writeInt(67);assertEquals(67, mmapBytes.readInt());}@Afterpublic void tearDown() {mmapBytes.free();}}
四. 总结
bytekit 是一个(),不依赖任何第三方库。它封装了字节数组、ByteBuffer 的操作,支持 mmap 常用的读写。
当然,它还可以封装 protobuf 的 ByteString 或者 Android 中的 Parcel,只需实现 Bytes 接口即可。
参考资料:
https://www.jianshu.com/p/2f663dc820d0
福利时间:
本人的 Kotlin 小册
(https://juejin.im/book/5af1c5ee6fb9a07a9f018368)
已在掘金预售,圣诞节送若干5折优惠券,可以在本文的底部留言向小编索取。

关注【Java与Android技术栈】
更多精彩内容请关注扫码:

ByteKit是一个用于Java的字节操作库,提供字节数组、ByteBuffer及mmap的封装,支持序列化、反序列化、深拷贝、哈希加密等功能,不依赖任何第三方库。
1万+

被折叠的 条评论
为什么被折叠?



