Использование XMLDecoder для преобразования закодированного XML в список <T> - PullRequest
6 голосов
/ 16 апреля 2010

Я пишу приложение, которое читает большое количество основных пользовательских данных в следующем формате; прочитав его, пользователь сможет искать его данные по электронной почте:

NAME             ROLE          EMAIL
---------------------------------------------------
Joe Bloggs       Manager       jbm@company.com
John Smith       Consultant    jsc@company.com
Alan Wright      Tester        awt@company.com
...

Проблема, которую я испытываю, заключается в том, что мне нужно хранить большое количество данных обо всех людях, которые работали в компании. Файл, содержащий эти данные, будет составляться на ежегодной основе просто для целей составления отчетов, но программе потребуется быстрый доступ к этим данным.

Способ, которым я стремлюсь получить доступ к этим файлам, состоит в том, чтобы иметь программу, которая запрашивает у пользователя имя уникального электронного адреса сотрудника, и чтобы программа затем возвращала имя и роль из этой строки файла. , Я поигрался с текстовыми файлами, но я борюсь с тем, как бы я обработал несколько столбцов данных, когда дело доходит до поиска этого большого файла.

В каком формате лучше хранить такие данные? Текстовый файл? XML? Размер меня не беспокоит, но я бы хотел найти его как можно быстрее. Файл должен содержать много записей, вероятно, со временем более 10 КБ.


РЕДАКТИРОВАТЬ: Я решил пойти с методом сериализации XML. Мне удалось заставить код для кодирования работать отлично, но код декодирования ниже не работает.

XMLDecoder d = new XMLDecoder(
               new BufferedInputStream(new FileInputStream("data.xml")));
List<Employee> list = (List<Employee>) d.readObject();
d.close();
for(Employee x : list) {
    if(x.getEmail().equals(userInput)) {
        // do stuff
    }
}

Когда программа нажимает List<Employee> list = (List<Employee>) d.readObject();, генерируется исключение, утверждающее, что «Сотрудник не может быть приведен к java.util.List». Я добавил к этому вознаграждение, и любой, кто может помочь мне решить эту проблему раз и навсегда, получит много приятных очков.

РЕДАКТИРОВАТЬ 2: Я немного больше посмотрел на проблему и наткнулся на Сериализация в качестве потенциального ответа. Если бы кто-нибудь мог посмотреть на это для меня, поскольку у меня нет опыта в сериализации или десериализации, я был бы очень благодарен. Он может предоставить объект без проблем, но мне действительно нужно вернуть его в том же формате, в котором он был (Список).

РЕДАКТИРОВАТЬ 3: Тьфу, эта проблема действительно начинает сводить меня с ума и, честно говоря, я начинаю думать, что это неразрешимая проблема. Если возможно, может кто-нибудь взглянуть на код и помочь мне найти решение?

Ответы [ 5 ]

5 голосов
/ 16 апреля 2010

Поскольку я думаю, что другие ответят на этот вопрос, посоветовав вам использовать внешнюю базу данных, я не буду:

Я предлагаю создать Java Bean, т.е.

public class Employee {

    public String name;
    public String role;
    public String email;

    public Employee() {}

    public Employee(String name, String role, String email) {
        setName(name);
        setRole(role);
        setEmail(email);
    }

    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }

    // etc. for other fields

}

И используйте java.beans.XMLDecoder и java.beans.XMLEncoder для сериализации / десериализации ArrayList<Employee>. (Вы можете прочитать больше о них здесь: http://java.sun.com/j2se/1.4.2/docs/api/java/beans/XMLEncoder.html используя более старый API, потому что я не знаю, какую версию вы используете.)

Затем вы можете искать в этом массиве, используя foreach:

XMLDecoder d = new XMLDecoder(
               new BufferedInputStream(new FileInputStream("data.xml")));
List<Employee> list = (List<Employee>) d.readObject();
d.close();
for(Employee x : list) {
    if(x.getEmail().equals(userInput)) {
        // do stuff
    }
}

Преимущество использования XML-сериализации перед «двоичной» сериализацией заключается в том, что вы также можете добавить новые поля в Employee позже, если вы также предоставите для них значения по умолчанию. Это делает данные гибкими для будущего использования.

Подробнее: http://java.sun.com/products/jfc/tsc/articles/persistence4/

Обновление:

XMLEncoder / XMLDecoder - лучшее решение, чем двоичная сериализация. Я советую вам сделать следующее.

Создайте новый класс-оболочку:

public class EmployeeList {

    private final ArrayList<Employee> list = new ArrayList<Employee>();

    public List<Employee> getList() {
        return this.list;
    }
    public setList(final List<Employee> list) {
        this.list.clear();
        this.list.addAll(list); // shallow copy
    }

    // add your search methods here, for example:
    public Employee getEmployee(String email) {
        ....
    }

}

Теперь вы можете использовать это EmployeeList в качестве оболочки. Используя следующий код, вы, возможно, увидите, что не так с XMLDecoder, когда он вызывает исключение приведения.

XMLDecoder d = new XMLDecoder(
           new BufferedInputStream(new FileInputStream("data.xml")));
final Object o = d.readObject();
System.out.println(o.getClass());
if(o instanceof EmployeeList) {
    EmployeeList el = (EmployeeList) o;

    el.getEmployee(userInput); // TODO
}else{
    System.out.println("Wrong format.");
}

Вам бы тоже пришлось сериализовать ваш EmployeeList:

EmployeeList el = ...;
XMLEncoder e = new XMLEncoder(...);
e.writeObject(el);
3 голосов
/ 16 апреля 2010

Как насчет базы данных? Вы можете использовать Derby или Hypersonic . Вы можете создать их встроенный экземпляр только для собственного использования приложения. Я использовал их во многих приложениях, где мне приходится манипулировать большим количеством данных. Hypersonic очень приятный и быстрый. Derby в комплекте с JDK, поэтому его удобная база данных для использования.

См. это для дерби и это для гиперзвуковых.

1 голос
/ 16 апреля 2010

Многие подходы будут работать. Если бы я не собирался использовать базу данных, я бы сохранял данные в сжатом файле с разделителями табуляции. Чтобы прочитать файл, я бы использовал:

 BufferedReader sourceReader = new BufferedReader(new InputStreamReader(
     new GZIPInputStream(new FileInputStream(srcFile))), 4096);

 String line = null;
 while (null != (line = sourceReader.readLine()) {
     String [] colData = line.split("\t");  // alternately use java.util.Scanner 
     // Create maps for columns you want to search on.
 }
 // report results by querying map

Чтобы записать в файл, получите буферизованную запись следующим образом:

   BufferedWriter destinationWriter = new BufferedWriter(new OutputStreamWriter(
       new GZIPOutputStream(new FileOutputStream(destination))));

   // do stuff
   destinationWriter.flush();
   destinationWriter.close();

Надеюсь, это поможет ....

0 голосов
/ 20 апреля 2010

Ваши критерии

Размер меня не беспокоит, но я бы хотел бы иметь возможность искать его как как можно быстрее. Файл будет нужно содержать много записей, вероятно, выше отметки 10К с течением времени

говорит, что XML не подходит.

Вы используете XML и сериализацию только тогда, когда

  • вы хотите иметь возможность редактировать файл вручную с помощью текстового редактора
  • вам нужно передать файл в качестве потока аргументов для RPC или межсистемного взаимодействия.

Если у вас нет острой необходимости ни в одном из указанных выше требований, я не могу быть убежден, что XML вообще следует использовать для хранения большого объема данных.

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

Я думаю, что хорошее решение - это hsqldb http://hsqldb.org/.

Какое преимущество вы получите по сравнению с использованием hsqldb, используя xml и сериализацию? Я считаю, что sql / jdbc / jdo намного удобнее и знакомее.

Если у меня нет веских причин для борьбы с использованием XML в качестве механизма персистентности, способного выполнять запросы, или из-за того, что sql / jdbc / jdo не является моей чашкой чая или у меня есть академическая элегантность, чтобы доказать, то мое ленивое отношение к завершению Задача как можно быстрее и грязнее будет использовать hsqldb. Кстати, лень - добродетель хорошего программиста.

Если вы думаете о сериализации / десериализации из / в объекты, JDO - идеальный путь. JDO - это интерфейс к базе данных, позволяющий вам записывать и извлекать данные как объекты.

http://en.wikipedia.org/wiki/Java_Data_Objects
http://www.informit.com/articles/article.aspx?p=212397.

Однако, если сохранение объектов не является вашим требованием, достаточно простого соединения jdbc:

Connection c = DriverManager.getConnection("jdbc:hsqldb:file:mydb", "SA", "");
0 голосов
/ 20 апреля 2010

Хорошо, мне наконец-то удалось решить проблему обработки объектов после того, как они были декодированы через ArrayList, а не через List<Employee>. Я использую XMLEncoder для кодирования ArrayList в XML-файл после разделения на отдельные части, а затем использую XMLDecoder, чтобы извлечь объекты, привести их к Employee и затем использовать их при необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...