C'est la méthode que j'ai proposée il y a quelque temps. Pas une meilleure pratique. J'aime l'orientation des objets (˘ω˘)
Tout d'abord, extrayez de InputStream vers l'octet []. Veuillez consulter ici pour savoir comment le retirer. Enveloppez-le pour créer un ByteBuffer (ci-après buf).
byte[] bin = BinUtil.readAll(stream);
ByteBuffer buf = ByteBuffer.wrap(bin);
(long)buf.getInt()
Il n'y a pas de concept de signe en Java (˘ω˘).
(long)buf.getInt () & 0xffffffffL
--Définissez l'interface du type de données.
Vous devez pouvoir obtenir et obtenir des données de buf. Préparez la compilation et la décompilation. La longueur et le décalage de la taille totale des données (décrits plus loin) sont également requis.
public interface DataTypeInterface<T> {
Integer getOffset();
void setOffset(Integer offset);
Integer getSize();
void setSize(Integer size);
void decompile(ByteBuffer buf);
void compile(ByteBuffer buf);
/**
*Obtenir des éléments enfants
*
* @retourner l'élément enfant
*/
T get();
/**
*Définir les éléments enfants
*
* @élément param Elément enfant
*/
void set(T item);
}
Un type dont la valeur interne peut être représentée par une primitive java (telle que String ou Long).
public abstract class SingleDataType<T> implements DataTypeInterface<T>{
/**
*Valeur interne
*/
private T value;
/**
*Position de début de l'objet dans le flux d'octets
*/
private Integer offset;
/**
*Taille d'octet de l'objet
*/
private Integer size;
@Override
final public Integer getOffset(){
return this.offset;
}
@Override
final public void setOffset(Integer offset){
this.offset= offset;
}
@Override
final public void setSize(Integer size) {
this.size = size;
}
@Override
public Integer getSize() {
return this.size;
}
public T get() {
return this.value;
}
public void set(T value) {
this.value = value;
}
}
Seulement les chiffres.
abstract public class NumericDataType<T extends Number> extends SingleDataType<T> {
@Override
final public T get() {
return super.get();
}
@Override
public void set(T val) {
super.set(val);
}
abstract public void setNumber(Number val);
}
LONG Fondamentalement fait long (゜ ∀ ゜)
public class LONG extends NumericDataType<Long> {
@Override
public void decompile(ByteBuffer buf) {
this.setOffset(buf.position());
this.set((long)buf.getInt());
}
@Override
public void compile(ByteBuffer buf) {
this.setOffset(buf.position());
buf.putInt(this.get().intValue());
}
public LONG(ByteBuffer buf) {
this.decompile(buf);
this.setSize(4);
}
public LONG(Long value) {
this.set(value);
this.setSize(4);
}
/**
*Validez et définissez la valeur
*
* @valeur de paramètre valeur
* @La plage des valeurs de jette IllegalArgumentException est-S'il est inférieur à 2147483648L ou supérieur à 2147483647L
*/
@Override
public void set(Long value) throws IllegalArgumentException {
/*1*/
if ( value < -2147483648L || 2147483647L < value) {
throw new IllegalArgumentException("La plage de valeurs dépasse les longueurs maximale et minimale");
}
/*2*/
super.set(value);
}
@Override
public void setNumber(Number val) {
this.set(val.longValue());
}
}
Il n'y a pas de concept de struct en Java (; ω;). Je ferai quelque chose avec des annotations et une réflexion
@Retention(RetentionPolicy.RUNTIME)
public @interface PROPERTY {
int order();
}
Énumérer les champs par réflexion, extraire uniquement ceux avec les annotations ci-dessus, les trier dans l'ordre et décompiler dans cet ordre.
public abstract class CompositeDataType implements DataTypeInterface<DataTypeInterface>{
protected Integer offset;
@Override
final public Integer getOffset(){
return this.offset;
}
@Override
final public void setOffset(Integer offset){
this.offset= offset;
}
@Override
public Integer getSize(){
return this.OrderedProperties()
.entrySet()
.stream()
.mapToInt(item -> item.getValue().getSize())
.sum();
}
@Override
@Deprecated
public void setSize(Integer size) {
throw new RuntimeException("Vous ne pouvez pas définir la taille d'un objet composite.");
}
@Override
public void decompile(ByteBuffer buf){
this.setOffset(buf.position());
for (Map.Entry<String, DataTypeInterface> item: this.OrderedProperties().entrySet()) {
try {
item.getValue().decompile(buf);
}catch (IllegalArgumentException e){
System.out.println("Clé("+ item.getKey() +")Les éléments enfants de sont ignorés");
e.printStackTrace();
}
}
}
@Override
public void compile(ByteBuffer buf) {
this.setOffset(buf.position());
for (Map.Entry<String, DataTypeInterface> item: this.OrderedProperties().entrySet()) {
try {
item.getValue().compile(buf);
}catch (IllegalArgumentException e){
System.out.println("Clé("+ item.getKey() +")Les éléments enfants de sont ignorés");
e.printStackTrace();
}
}
}
protected Map<String,DataTypeInterface> OrderedProperties() {
List<Field> fields=new ArrayList<>();
Class c= this.getClass() ;
while(c != null){
fields.addAll(java.util.Arrays.asList(c.getDeclaredFields()));
c = c.getSuperclass();
}
List<Field> paramfields = fields
.stream()
.filter(f -> f.getAnnotation(PROPERTY.class) != null)
.collect(Collectors.toList());
Collections.sort(paramfields, (Field o1, Field o2) -> {
PROPERTY or1 = o1.getAnnotation(PROPERTY.class);
PROPERTY or2 = o2.getAnnotation(PROPERTY.class);
if (or1 != null && or2 != null) {
return or1.order() - or2.order();
}
return o1.getName().compareTo(o2.getName());
}
);
Map<String, DataTypeInterface> m = new LinkedHashMap<>();
try {
for (Field f : paramfields) {
f.setAccessible(true);
m.put(f.getName(), (DataTypeInterface) f.get(this));
}
} catch (IllegalAccessException e) {
throw new RuntimeException("champ("+ fields.toString() +"Ne peut pas accéder");
}
return m;
}
@Override
public DataTypeInterface get() {
return null;
}
@Override
public void set(DataTypeInterface item) {
}
}
Si vous avez une structure de données, utilisez-la comme suit.
public class Version extends CompositeDataType {
@PROPERTY(order = 1)
public LONG version = new LONG();
@PROPERTY(order = 2)
public LONG subVersion = new LONG();
}
Vous pouvez réutiliser ce que vous faites.
public class Data1 extends CompositeDataType {
@PROPERTY(order = 1)
public Version version = new Version();
@PROPERTY(order = 2)
public LONG data1 = new LONG();
}
Ce sont les bases, et 2 est pour les données de tableau et les données de décalage.
Recommended Posts