Как сделать этот класс ТЛВ читатель выглядеть лучше и работать ровнее?


Я очень новой для Java и пытаюсь улучшить мои навыки немного двоичного файла читатель. Выбран был ТЛВ формате. Я выбрала, что для будучи достаточно простым, но не все так просто. Также у меня были некоторые конкретные примеры с хорошей документацией, которую я мог бы следовать за расшифровку.

Читатель работает, но я в конечном итоге с классом, который кажется слишком большой, чтобы быть правым. Я интересно, если кто может сломать этот код в что-то более крепкое.

package tlv;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import tlv.errors.MissingI10ParameterException;
import tlv.errors.ParseI10ParameterException;
import tlv.errors.TLVFileException;

/**
 * Represents a TLV file.
 * Expects class File, which represents a TLV file formated as:
 *  [HEADER]
 *  [LogicalBlock-1]
 *      [DataSegmentHeader-1]
 *      [DataSegment-1]
 *      [DataSegmentTrailer-1]
 *      (...)
 *      [DataSegmentHeader-n]
 *      [DataSegment-n]
 *      [DataSegmentTrailer-n]
 *  
 */
public class DiriTlvFile {

    ArrayList<LogicalBlock> dirisegs = new ArrayList<LogicalBlock>();
    int tbc = 114;

    public DiriTlvFile(File tlv) throws TLVFileException {

        DataInputStream dis = null;
        try {

            // Here BufferedInputStream is added for fast reading.
            dis = new DataInputStream(new BufferedInputStream(new FileInputStream(tlv)));

            // Header data
            byte[] ba = new byte[3];

            /* This is the fixes header added
             We just skip it straight away. */
            dis.skipBytes(114);
            LogicalBlock lb = null;

            // Iterate over main file parts
            while (dis.available() > 0) {
                if (dis.read(ba, 0, 3)!= 3)
                    throw new TLVFileException("Error reading DataSegmentID (wrong byte count) @" + tbc);
                tbc += 3;
                String headerId = new String(ba);


                // File header
                if (headerId.equalsIgnoreCase("I01")) {

                    lb = new LogicalBlock();
                    // Skip uninteresting part of header
                    dis.skipBytes(50);
                    tbc += 50;

                // Data Segment body
                } else if (headerId.equalsIgnoreCase("I10")) {

                    if (lb == null)
                        throw new TLVFileException( "Logical Block was not initiated! (Missing I01 structure in file).");

                    byte[] dsheader = new byte[25];
                    if (dis.read(dsheader, 0, 25) != 25) // Head of the DS
                        throw new TLVFileException( "Error reading DataSegmentHeader (I10, wrong byte count) @ " + tbc);
                    tbc += 25;

                    int dssize = (dsheader[24] & 0xFF) - 1; // Size of DS body (+the header itself?)
                    byte[] dsbody = new byte[dssize];   // Body of DS 


                    // Read DataSegmentBody
                    if (dis.read(dsbody, 0, dssize) != dssize)
                        throw new TLVFileException( "Error reading DataSegmentBody (I10, wrong byte count) @ " + tbc);
                    tbc += dssize;

                    // Create the datasegments
                    try {
                        lb.addDataSegment(new I10DataSegment(headerId, dsheader, dsbody));
                    } catch (MissingI10ParameterException e) {
                        // TODO - Improve this message using the mandatory parameter list from the exception
                        throw new TLVFileException("Error parsing DataSegment body (I10) : Missing one of mandatory parameters.");
                    } catch (ParseI10ParameterException e) {
                        throw new TLVFileException("Error parsing DataSegment body (I10) : Could not parse DataSegmentParameters.");
                    }

                } else if (headerId.equalsIgnoreCase("I03")) {
                    // total records read
                    byte[] trailertotrecs = new byte[3];
                    // Have left the loop, means it found the footer
                    byte[] trailerbody = new byte[4];
                    if (dis.read(trailerbody, 0, 4) != 4) // Trailer Body
                        throw new TLVFileException( "Error reading Trailer Body (I03, wrong byte count) @ " + tbc);
                    tbc += 4;
                    System.arraycopy(trailerbody, 1, trailertotrecs, 0, 3);
                    // TODO - compare the number of records read with the information in the footer
                    dirisegs.add(lb);
                } else {
                    throw new TLVFileException("Unknown Segment ID found");
                }
            }
            // dispose all the resources after using them.
            dis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
          e.printStackTrace();
        }
    }

    public Iterator<LogicalBlock> getLogicalBlocks() {
        return dirisegs.iterator();
    }

    public Iterator<DataSegment> getDataSegments(){
        ArrayList<DataSegment> a = new ArrayList<DataSegment>();
        Iterator<LogicalBlock> i = getLogicalBlocks();
        while (i.hasNext()){
            Iterator<DataSegment> j = i.next().getDataSegments();
            while (j.hasNext()){
                a.add((DataSegment)j.next());
            }
        }
        return a.iterator();
    }
}

P. S.: Я тут опущу другие классы, так как они практически только байт-анализа.



3240
1
задан 6 апреля 2011 в 04:04 Источник Поделиться
Комментарии
2 ответа


  • Программа против интерфейсы, например, список dirisegs = новый ArrayList();

  • Использовать имена переменных со смыслом, например, byteCount вместо ТВС

  • Не пишите е.печатные(), сделать что-то полезное (распространения ошибки, журнал ошибок...)

  • Ваш DataInputStream не будет рядом в случае ошибки. Вы должны двигаться закрытия в finally пункт (конечно, там необходимо дополнительно попробовать-поймать)

  • Конструктор-это путь длинный, разделить его

  • Почему бы вам не вернуть список в getDataSegments (у вас уже есть)? Итератор является менее полезным

  • Переименовать getLogicalBlocks на итератор() и добавить расширяется Iterable в вашем классе, то вы можете использовать класс в усиленном циклов.

  • Попробуйте сделать операций "атомный", например, пачка чтение из потока и увеличение счетчика в немного способ:

.

public void read(DataInputStream dis, byte[] buffer, String errorMessage) 
throws IOException,TLVFileException {
if (dis.read(buffer, 0, buffer.length) != buffer.length)
throw new TLVFileException(errorMessage + tbc);
tbc += buffer.length;
}

getDataSegments может быть сокращен до:

public Iterator<DataSegment> getDataSegments(){
List<DataSegment> result = new ArrayList<DataSegment>();
for(LogicalBlock lb : dirisegs) {
Iterator<DataSegment> segments = lb.getDataSegments();
while (segments .hasNext()){
result.add(segments .next());
}
}
return result.iterator();
}

4
ответ дан 21 апреля 2011 в 06:04 Источник Поделиться

Во-первых, я должен упомянуть, что я не очень понимаю формат. Вы говорите, что это TLV, но ты, похоже, читал в основном фиксированной длины куски.

Я разделю задачи анализа и данные. Я мог бы написать своего рода TLVInputStream или TLVParser класс, который имеет метод readChunk, который читает один ТЛВ трехместный из базового потока и возвращает его. Использование как:

TLVInputStream input = new TLVInputStream(new FileInputStream(someFile));
Chunk chunk = input.readChunk();

Конструктор будет делать заголовка пропуск. readChunk бы поймать EOFException от чтения первого (и только первого) байта в теге, и смириться с этим, возвращая значение null, чтобы указать на конец файла (как командой bufferedreader.с readline возвращает значение null в конец файла). EOFExceptions нигде в блоке, который должен быть пройден, так как они действительно являются ошибками.

Я бы не расшифровывая конкретных видах кусок в readChunk способ. А чем обрабатывать кусок длиной как-то для проверки, я использовал бы их для контроля чтения. readChunk бы прочитать кусок заголовка, прочитайте длину, то читать столько байтов из входного сигнала, и вернуть кусок. Проверка длины частей принадлежит в более высоком уровне, чем код ИО.

Тогда у меня был бы отдельный класс, который держит чанки. Назвать это ChunkFile или что-то. Что содержит куски, и делать проверку на них (например, проверяя длину), так как они добавляются. Если позже вы хотели, чтобы добавить методы для работы на куски, они пойдут здесь.

Я бы третий, маленький, класс, который использует TLVInputStream для чтения файла и сделать ChunkFile объекта. Это достаточно просто, что это может быть статический метод фабрики на TLVInputStream.

Есть несколько мелких деталей, я бы изменила. Если подсчитывать общее количество байтов важно, затем переместите читать и считать операций в один метод, который делает и то и другое, и постоянно использовать. Это означает, что вы не должны помнить, чтобы обновить счетчик, когда вы читаете. Вы много Дис.читать(буфер buf, 0, лен) == лен - вы должны использовать readFully для этого.

1
ответ дан 6 апреля 2011 в 04:04 Источник Поделиться