我正在使用Java中的Memory Mapped文件。我有一个特定的用户ID数据以Avro二进制编码格式存储在内存映射文件中。
内存映射文件包含两个主要部分: - 标题,用作完整文件内容的索引,专门回答文件的问题,并为每个用户的数据提供偏移量。 - 一个正文,后跟给定偏移量的文件中每个用户的数据。
标题
version 4 bytes
last_modified_date 8 bytes
users 4 bytes
shards 4 bytes
the shards N * 4 bytes
num_hash_index 4 bytes
num_chain_slots 4 bytes
user offset/size index num_hash_index * num_chain_slots * (8 bytes + 8 bytes + 4 bytes)
现在标题后面是正文,如下所示。
车身
number of records 2 bytes how many records does this user have?
a repeated sequence of records variable size as described below
所有记录都遵循此规范:
attribute key X bytes a string of the users key.
key delimiter 1 bytes '\0'
client id 2 bytes some client id
last modified time (in ms) 8 bytes This is the last modified time for this attribute in ms.
length of the avro binary data 2 bytes actual length of avro binary data
the binary avro data or text Y bytes Length given by the previous field.
现在我已经使用上述格式生成了很多文件。我需要从Java程序中读取此文件。在Java中执行此操作的最佳方法是什么?这是我第一次使用Memory Mapped文件,所以试着理解我该如何处理这个?
FileChannel fc = new RandomAccessFile(new File("c:/tmp/file.txt"), "rw").getChannel();
现在我不知道该怎么办?任何例子都会帮助我更好地理解。
答案 0 :(得分:1)
这应该这样做。关键是DataInputStream中读取和转换字节的方法。我认为字节顺序是合适的。
ByteBuffer buf = ByteBuffer.allocate( 9999 ); // capacity
int nRead = fc.read( buf );
InputStream is = new ByteArrayInputStream( buf.array() );
DataInputStream dis = new DataInputStream( is );
int version = dis.readInt(); // 4 bytes
long timestamp = dis.readLong(); // 8 bytes
int numUsers = dis.readInt(); // 4 bytes
等等。
关于身体的更多细节
不需要存储密钥分隔符('\ 0')和avro数据的长度,这由字节数组的长度表示。我使用int来存储短整数,只是为了安全起见(Java中没有unsigned short),
public class UserAttribute {
private final String attributeKey;
private final int schemaId; // unsigned short
private final long lastModifiedDate;
private final byte[] avroBinaryData; // preceded by length: unsigned short
// constructor and getters here
}
int numberOfAttributes = dis.readShort();
List<UserAttribute> ual = new ArrayList<>( numberOfAttributes );
for( int iAttr = 0; iAttr < numberOfAttributes; ++iAttr ){
// read values for one attribute, create UserAttribute object
UserAttribute ua = new UserAttribute();
StringBuilder sb = new StringBuilder();
for(;;){
int ub = dis.readUnsignedByte(); // can this be in ISO-8859-1 > 0x80?
if( ub == 0 ) break;
sb.append( (char)ub );
}
ua.setAttributeKey( sb.toString() );
ua.setSchemaId( dis.readUnsignedShort() );
ua.setLastModifiedDate( dis.readLong() );
int loabd = dis.readUnsignedShort();
byte[] abd = new byte[loabd];
for( int ib = 0; ib < loabd; ++ib ){
abd[ib] = dis.readByte();
}
ua.setAvroBinaryData();
ual.add( ua );
}
另外,我认为阅读分片应该是
int numShards = dis.readInt(); // 4 bytes 1..101
int[] shards = new int[numShards];
for( il = 0; il < numShards; ++il ){
shards[il] = dis.readInt(); // N * 4 bytes Where N is the number of shards
}
甚至更晚内存映射
int read = ...;
FileChannel fc = new RandomAccessFile(file, "rw").getChannel();
ByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, read );
buffer.order(ByteOrder.BIG_ENDIAN);
这导致包含文件数据的给定长度的ByteBuffer。如果文件大于0x7fffffff,则必须以块的形式映射,这可以使用相同的FileChannel方法,即map。