使用XMLDecoder将编码的XML转换为List <t> </t>

时间:2010-04-16 00:13:06

标签: java

我正在编写一个应用程序,它按以下格式读取大量基本用户详细信息;一旦读入,它允许用户使用他们的电子邮件搜索用户的详细信息:

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

我遇到的问题是我需要存储在公司工作过的所有人的大量细节。包含这些详细信息的文件将每年编写,仅用于报告目的,但该程序需要能够快速访问这些详细信息。

我打算访问这些文件的方法是让程序向用户询问工作人员的唯一电子邮件的名称,然后程序从文件的该行返回名称和角色。我玩过文本文件,但在搜索这个大文件时,我正在努力处理多列数据。

存储此类数据的最佳格式是什么?一个文本文件? XML?尺寸不会打扰我,但我希望能够尽快搜索它。该文件需要包含大量条目,可能会随着时间的推移超过10K标记。


编辑:我决定采用XML序列化方法。我已经设法让Encoding的代码完美运行,但下面的解码代码不起作用。

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();时,抛出一个异常,声称“Employee不能转换为java.util.List”。我已经为此添加了一笔赏金,任何可以帮助我一劳永逸地解决这个问题的人都会得到很多可爱的点。

编辑2:我对此问题的看法更多,并且遇到了Serialization作为潜在答案。如果有人可以为我调查,因为我没有序列化或反序列化的经验,我将非常感激。它可以提供一个没有任何问题的Object,但我真的需要以与它进入的相同格式返回它(List)。

编辑3:呃,这个问题真的开始让我发疯,说实话我开始认为这是一个无法解决的问题。如果可能,有人可以查看代码并帮助我提供解决方案吗?

5 个答案:

答案 0 :(得分:5)

由于我猜其他人会建议您使用外部数据库来回答这个问题,我不会:

我建议创建一个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.XMLDecoderjava.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);

答案 1 :(得分:3)

数据库怎么样?您可以使用DerbyHypersonic。您可以创建它们的嵌入式实例,仅供您自己的应用程序使用。我已经在许多应用程序中使用它们,我必须处理大量数据。 Hypersonic是非常好的和快速的。 Derby与JDK捆绑在一起,因此可以方便地使用它。

有关Derby的信息,请参阅this;有关Hypersonic的信息,请参阅this

答案 2 :(得分:1)

许多方法都有效。如果我不打算使用数据库,我会将数据存储在一个带有gzip的制表符分隔文件中。要阅读我将使用的文件:

 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();

希望有所帮助....

答案 3 :(得分:0)

好的,我终于设法解决了在通过ArrayList而不是List<Employee>解码后处理对象的问题。我使用XMLEncoderArrayList编码为XML文件,一旦拆分成单独的部分,然后我使用XMLDecoder取出对象,将它们转换为Employee,然后将它们用作需要的。

答案 4 :(得分:0)

您的标准

  

尺寸不会打扰我,但我会   喜欢能够搜索它   尽快。该文件将   需要包含很多条目,   随着时间的推移可能超过10K标记

说XML不合适。

仅在

时使用XML和序列化
  • 您希望能够使用文本编辑器手动编辑文件
  • 您需要将该文件作为参数流传递给RPC或进行系统间通信。

如果您没有迫切需要满足上述任何一项要求,我无法确信是否应该使用XML来保存大量数据。

您需要的是单个文件数据库,以便您可以使用您的应用移动文件。

我认为一个好的解决方案是hsqldb http://hsqldb.org/

使用xml和序列化使用hsqldb会有什么好处?我发现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", "");