【问题标题】:How to sort records from text file and store into binary?如何对文本文件中的记录进行排序并存储为二进制文件?
【发布时间】:2015-09-02 22:48:30
【问题描述】:

我有一个输入文本文件,它基本上是一群人。我需要对所有记录进行排序(按姓氏、名字),然后将所有记录存储到二进制文件中。到目前为止,我所做的是创建一个 DataRecord 对象,该对象具有所有适当的字段和 getter/setterscompareTo。总的来说,我有一个DataRecord 类型的ArrayList 用于排序目的。

public class DataRecord implements Comparable<DataRecord>{

private String lastName, firstName, middleName, suffix, cityOfBirth;
private int monthOfBirth, dayOfBirth, yearOfBirth;
private char gender;


//getters
public String getLastName() { return this.lastName;}
public String getFirstName() { return this.firstName;}
public String getMiddleName() { return this.middleName;}
public String getSuffix() { return this.suffix;}
public String getCityOfBirth() { return this.cityOfBirth;}
public int getMonthOfBirth() { return this.monthOfBirth;}
public int getDayOfBirth() { return this.dayOfBirth;}
public int getYearOfBirth() { return this.yearOfBirth;}
public char getGender() { return this.gender;}

//setters
public void setLastName(String lastName) { this.lastName = lastName;}
public void setFirstName(String firstName) { this.firstName = firstName;}
public void setMiddleName(String middleName) { this.middleName = middleName;}
public void setSuffix(String suffix) { this.suffix = suffix;}
public void setCityOfBirth(String cityOfBirth) { this.cityOfBirth = cityOfBirth;}
public void setMonthOfBirth(int monthOfBirth) { this.monthOfBirth = monthOfBirth;}
public void setDayOfBirth(int dayOfBirth) { this.dayOfBirth = dayOfBirth;}
public void setYearOfBirth(int yearOfBirth) { this.yearOfBirth = yearOfBirth;}
public void setGender(char gender) { this.gender = gender;}

public DataRecord(){

}

//constructor to make copy of record passed in
public DataRecord(DataRecord copyFrom){
    this.lastName = copyFrom.getLastName();
    this.firstName = copyFrom.getFirstName();
    this.middleName = copyFrom.getMiddleName();
    this.suffix = copyFrom.getSuffix();
    this.monthOfBirth = copyFrom.getMonthOfBirth();
    this.dayOfBirth = copyFrom.getDayOfBirth();
    this.yearOfBirth = copyFrom.getYearOfBirth();
    this.gender = copyFrom.getGender();
    this.cityOfBirth = copyFrom.getCityOfBirth();
}

@Override
public int compareTo(DataRecord arg0) {
    // TODO Auto-generated method stub
    int lastNameCompare;

    //check if the last names are the same, if so return the first name comparison
    if ((lastNameCompare = this.getLastName().compareTo(arg0.getLastName())) == 0){
        return this.getFirstName().compareTo(arg0.getFirstName());
    }

    //otherwise return the last name comparison
    return lastNameCompare;

}

public String toString(){
    return this.getLastName() + ' ' + this.getFirstName();
}

}

public class IOController {

  public static void main(String[] args) throws IOException {
    File inputFile; // input file
    RandomAccessFile dataStream = null; // output stream
    ArrayList<DataRecord> records = new ArrayList<DataRecord>();

    BufferedReader reader = new BufferedReader(new FileReader(args[0]));
    try {
        String sb;
        String line = reader.readLine();
        String[] fields;

        // loop through and read all the lines in the input file
        while (line != null) {
            DataRecord currentRecord = new DataRecord();

            // store the current line into a local string
            sb = line;

            // create an array of all the fields
            fields = sb.split("\t");
            // set the fields for the DataRecord object
            currentRecord.setLastName(fields[0]);
            currentRecord.setFirstName(fields[1]);

            // check other fields exist
            if (fields.length >= 3) {
                currentRecord.setMiddleName(fields[2]);
                currentRecord.setSuffix(fields[3]);
                currentRecord.setMonthOfBirth(Integer.parseInt(fields[4]));
                currentRecord.setDayOfBirth(Integer.parseInt(fields[5]));
                currentRecord.setYearOfBirth(Integer.parseInt(fields[6]));
                currentRecord.setGender(fields[7].charAt(0));
                currentRecord.setCityOfBirth(fields[8]);
            }

            // add the current record to the array list of records
            records.add(currentRecord);
            line = reader.readLine();
        }
    } finally {
        reader.close();
      //Collections.sort(records);
    }

    for (int i = 0; i < 5; i++) {
        System.out.println(records.get(i));
    }

}

}

我的问题是,如果我使用临时的DataRecord(名为currentRecord)来读取字段,然后添加到ArrayList,我在ArrayList 的每条记录中都有所有相同的数据。如果我将该数据复制到另一个 DataRecord 对象(使用我传入 DataRecord 的构造函数),我会用完堆空间。

records.add(new DataRecord(currentRecord));
line = reader.readLine();

是我使用ArrayList 的错误吗?

【问题讨论】:

  • 你的文件有多大?如果您的文件大于可用内存,您将不得不使用外部排序方法。 en.wikipedia.org/wiki/External_sorting如果你有足够的内存,你可以增加java堆内存。
  • 代码看起来不错!就像@LuiggiMendonca 所说,我想象“\t”中的错误。
  • 为什么要切换到“\\t”?在这种情况下,它不会在制表符上拆分,对吗?
  • 使用“\\t”或“\t”没问题。阅读这篇文章:stackoverflow.com/questions/3762347/…。我仍然认为问题出在您的文件中。您是否尝试使用另一个输入文件运行您的程序?

标签: java sorting arraylist


【解决方案1】:

您使用相同的对象引用来添加ArrayList,并在每次迭代时更新它。只需在每次迭代时创建对象的新实例:

while (line != null) {
    DataRecord currentRecord = new DataRecord();
    // rest of the code...
    records.add(currentRecord);
}
//sort the list

作为最佳实践,在尽可能窄的范围内声明变量。

由于堆空间不足,您可以尝试使用-Xmx 参数向您的进程添加更多内存。如果您正在执行该过程的 PC 中缺少 ram,则使用另一种替代方法,例如将文件拆分为小块,对每个新文件进行排序,然后在这些文件中的数据之间使用合并排序的派生。

【讨论】:

  • 当我这样做时,我仍然用完了堆空间:线程“main”中的异常 java.lang.OutOfMemoryError: Java 堆空间
  • 对不起,我认为堆空间错误是我打电话给Collections.sort
  • Nvm,我注释掉了排序,它仍然有一个堆空间错误。该文件是 43.7mb,没有办法。
  • 并且在线引发错误:fields = sb.split("/t");
  • 你重写了记录类的equal方法吗?我建议也覆盖 hashCode 方法。发布完整代码。
【解决方案2】:

是我使用 ArrayList 的错误吗?

没有。

您的错误是以下一项或两项:

  • 试图同时在内存中保存一个大文件的信息内容。另一种方法是流式传输数据;例如读取记录、写入记录、读取、记录、写入记录等(当然,这样做的可行性取决于您的“二进制”文件表示的性质。)

  • 尝试使用太小的堆运行。 java 命令文档解释了如何增加堆大小,但显然这种方法存在实际限制。

为了记录,这也是一个错误:

    records.add(currentRecord);

如果您这样做,您最终会得到一个列表,其中包含(仅)N 个 CSV 输入文件中最后一条记录的副本。如果您要在列表中构建内存中的副本,则需要为每一行创建一个新的DataRecord 对象。


郑重声明,从长远来看,更改为 LinkedList 不会有任何帮助。通过附加到使用new ArrayList() 创建的列表创建的ArrayList最大空间使用量大约是引用大小的3 倍。对于LinkedList,空间使用量是引用大小的 3 倍 + 每个条目额外增加 2 个字。

【讨论】:

  • 您能详细说明要点吗?至于第三件事,我意识到但认为使用新对象会导致堆空间错误。
  • 实际上我现在几乎可以肯定所有DataRecords 都导致了内存问题
猜你喜欢
  • 2017-02-02
  • 1970-01-01
  • 2019-02-04
  • 2011-09-27
  • 1970-01-01
  • 2010-10-18
  • 2016-07-31
  • 2018-04-29
  • 2022-01-18
相关资源
最近更新 更多