2015-08-25 2 views
0

Мне нужно разработать синтаксический анализатор для формата обмена двоичными сообщениями, то есть анализатора сообщений, который анализирует двоичное сообщение в представлении Java-объекта. Я хотел бы спросить, какие полезные шаблоны можно использовать для реализации парсера самым гибким способом. Может ли кто-нибудь описать это в двух словах или предоставить ресурсы для чтения?Написание парсера для формата двоичных сообщений

+0

https://github.com/jparsec/jparsec –

+0

Возможно, вы можете попробовать прочитать о том, как [буферы протокола Google] (https://developers.google.com/protocol-buffers/docs/encoding) разработаны (или просто используйте их!) –

+0

Зависит от того, что вы подразумеваете под «парсером». Обычно [парсер] (https://en.wikipedia.org/wiki/Parsing) читает текст, а не двоичные данные. – Andreas

ответ

2

Поскольку вы пытаетесь читать двоичные данные и преобразовывать их в Java-объект, существует много подходов, но, во-первых, вы должны знать структуру/протокол своего двоичного файла.

Образец, который я покажу вам, это стиль, которым я (если бы был вами) был использован для этого сценария.

Убедитесь, что у вас есть входной поток, который будет передавать ваши двоичные данные. Если у вас есть массив байтов, создайте ByteArrayInputStream.

В графе объектов каждый узел/объект должен реализовывать что-то вроде метода parseIn (InputStream s).

public class Parent extends ArrayList<Child> { 
    int age; 
    // ... more code here 
    public void parseIn(InputStream is) throws IOException { 
     // .. logic to read the stream into this instance. 
     DataInputStream dis = new DataInputStream(is); 
     this.age = dis.readInt(); 

     // .. if necessary 
     Child c = new Child(); 
     c.parseIn(InputStream is); 
     this.add(c); 
    } 
    // ... more code here 
} 

public class Child { 
    int height; 
    short weight; 
    Date birthdate; 
    public void parseIn(InputStream is) throws IOException { 
     // .. logic to read the stream into this instance. 
     DataInputStream dis = new DataInputStream(is); 
     height = dis.readInt(); 
     weight = dis.readShort(); 
     birthdate = new Date(dis.readLong()); 
    } 
} 

Итак, когда вы получите ваш поток, вы просто

InputStream stream = this.getInputStream(); 
Parent p = new Parent(); 
parent.parseIn(stream); 

И так далее, и так далее.

Несколько раз вам необходимо прочитать базовый поток, чтобы вы могли прочитать его вперед. Например, при чтении строковых данных в двоичном потоке. Либо вы продолжаете читать байт за байтом, пока не найдете байт терминатора (как символ окончания 0 стиля стиля C). Или указать длину строки в первом байте, а затем прочитать массив байтов этой длины.

Надеюсь, вы получите Идею. И я надеюсь, что это поможет.

+1

Осторожно: используйте DataInputStream только в том случае, если входной поток был создан с помощью java DataOutputStream. –

+0

Я не поклонник отсутствия конечных полей в этом решении. – brain

+0

Java использует BigEndian, когда число чтения/записи больше 8 бит. И DataOutputStream использует для этой цели bigendian для CMIIW. IETF сделал межсетевое взаимодействие BigEndian (RFC 1700) ... Я понимаю, что может быть случай для LittleEndian, но я думаю, у ByteBuffer есть некоторое решение вокруг LittleEndian. Во всяком случае, вышеприведенные фрагменты только для того, чтобы выразить шаблон. Не будем подробно рассказывать о том, как вы читаете байт по байту в терминах little/big endian. Таким образом, использование DataInputStream может быть использовано или заменено наиболее подходящим случаем. –

Смежные вопросы