0

对于我的生活,我无法弄清楚这些代码有什么问题..保存以保持覆盖本身并且加载不会加载已经存在的数据..我已经搜索过这段代码,但似乎人们使用不同的代码..请帮我结束我的头痛

// Write to file
static void writeToFile(Customer c[], int number_of_customers) throws IOException {
    // set up file for output
    // pw used to write to file
    File outputFile = new File("Customers.dat");
    FileOutputStream fos = new FileOutputStream(outputFile);
    PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos));

    int i = 0;
    do {
        pw.println(c[i].getName());
        pw.println(c[i].getNumber());
        i++;
    } while (i < number_of_customers);
    pw.println(0);
    pw.println(0);
    pw.close();
}

// Read from file
public static int readFromFile(Customer c[]) throws IOException {
    // set up file for reading
    // br used to read from file
    File inputFile = new File("Customers.dat");
    FileInputStream fis = new FileInputStream(inputFile);
    BufferedReader br = new BufferedReader(new InputStreamReader(fis));

    String cus;
    int l = -1;
    // Subtract AND assignment operator, It subtracts right operand from the
    // left operand and assign the result to left operand
    int all_customers = 0;
    do {
        l++;
        c[l] = new Customer();
        c[l].cus_name = br.readLine();
        cus = br.readLine();
        c[l].cus_no = Integer.parseInt(cus);
        all_customers++;

    } while (c[l].cus_no != 0); // end while

    br.close(); // end ReadFile class
    return all_customers - 1;
}
4

2 回答 2

1

修复写入方法的另一种方法是使用 FileOutputStream 构造函数,该构造函数允许您请求将数据附加到文件末尾。

FileOutputStream fos = new FileOutputStream(outputFile, true);

这确实假设您始终编写完整的最终记录,并在其后加上行尾,即使在错误条件下也是如此。您仍然必须使用其他解决方案(读取和合并)来处理这种情况,但是如果需要,后续运行可以检测并处理它。所以我描述的附加解决方案并不那么健壮。

于 2016-03-19T16:37:47.117 回答
1

您的代码存在许多问题。

先看看你的readFromFile方法:

  • 您正在传递一个数组,您的方法正在填充它找到的所有记录。如果文件中的客户多于阵列中的空间,会发生什么情况?(提示:ArrayIndexOutOfBoundsException是一个东西)
  • 您正在解析从文件中读取为字符串的整数。如果文件损坏并且读取的行不是整数会发生什么?
  • 要读取的文件的名称是硬编码的。这应该是一个常量或配置选项。出于编写方法的目的,最好将其设为参数。
  • 您正在打开文件并在方法中读取它。出于单元测试的目的,您应该将其拆分为单独的方法。
  • 通常,您应该使用Collections类而不是数组来保存对象列表。
  • Customer直接在readFromFile方法中访问属性。您应该使用访问器方法。

Collections基于方法

这是我建议的基于使用CollectionsAPI 的重写:

public static List<Customer> readFromFile(String filename) throws IOException {
    // set up file for reading
    // br used to read from file
    File inputFile = new File(filename);
    FileInputStream fis = new FileInputStream(inputFile);
    BufferedReader br = new BufferedReader(new InputStreamReader(fis));

    List<Customer> customers = readFromStream(br);

    br.close(); // end ReadFile class

    return customers;
}

这使用此方法来实际读取内容:

public static List<Customer> readFromStream(BufferedReader br) throws IOException {

    List<Customer> customerList = new LinkedList<>();

    // Subtract AND assignment operator, It subtracts right operand from the
    // left operand and assign the result to left operand
    boolean moreCustomers = true;
    while (moreCustomers) {
        try {
            Customer customer = new Customer();
            customer.setName(br.readLine());
            String sCustNo = br.readLine();
            customer.setNumber(Integer.parseInt(sCustNo));
            if (customer.getNumber() == 0) {
                moreCustomers = false;
            }
            else {
                customerList.add(customer);
            }
        }
        catch (NumberFormatException x) {
            // happens if the line is not a number.
            // handle this somehow, e.g. by ignoring, logging, or stopping execution
            // for now, we just stop reading
            moreCustomers = false;
        }
    }

    return customerList;
}

对 使用类似的方法writeToFile,我们得到:

static void writeToFile(Collection<Customer> customers, String filename) throws IOException {
    // set up file for output
    // pw used to write to file
    File outputFile = new File(filename);
    FileOutputStream fos = new FileOutputStream(outputFile);
    PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos));

    writeToStream(customers, pw);

    pw.flush();
    pw.close();
}

static void writeToStream(Collection<Customer> customers, PrintWriter pw) throws IOException {

    for (Customer customer: customers) {
        pw.println(customer.getName());
        pw.println(customer.getNumber());
    }
    pw.println(0);
    pw.println(0);

}

但是,我们仍未解决您的主要问题。您似乎想在调用时将文件内容与内存中的客户合并writeToFile。我建议您为此引入一种新方法。这使现有方法更简单:

static void syncToFile(Collection<Customer> customers, String filename) throws IOException {

    // get a list of existing customers
    List<Customer> customersInFile = readFromFile(filename);

    // use a set to merge
    Set<Customer> customersToWrite = new HashSet<>();

    // first add current in-memory cutomers
    customersToWrite.addAll(customers);

    // then add the ones from the file. Duplicates will be ignored
    customersToWrite.addAll(customersInFile);

    // then save the merged set
    writeToFile(customersToWrite, filename);
}

哦……我差点忘了:使用 aSet来合并文件和内存列表的神奇之处在于你equals()在类中实现方法Customer。如果你覆盖equals(),你也应该覆盖hashCode()。例如:

public class Customer {
    @Override
    public boolean equals(Object obj) {
        return (obj != null) && (obj instanceof Customer) && (getNumber() == ((Customer)obj).getNumber());
    }

    @Override
    public int hashCode() {
        return getNumber()+31;
    }
};

CustomerList基于方法

如果您不能使用CollectionsAPI,那么第二好的方法是编写自己的集合类型,该集合类型支持相同的操作,但由数组(或链表,如果您了解的话)支持。在您的情况下,它将是客户列表。我将调用类型CustomerList

分析我们现有的代码,我们需要一个实现add方法和遍历列表的方法的类。忽略Iterators,我们将使用 agetLength和 a getCustomer(按索引)完成后者。对于同步,我们还需要一种方法来检查客户是否在列表中,因此我们将添加一个contains方法:

public class CustomerList {

    private static final int INITIAL_SIZE = 100;
    private static final int SIZE_INCREMENT = 100;

    // list of customers. We're keeping it packed, so there
    // should be no holes!
    private Customer[] customers = new Customer[INITIAL_SIZE];
    private int numberOfCustomers = 0;

    /**
     * Adds a new customer at end. Allows duplicates.
     * 
     * @param newCustomer the new customer to add
     * @return the updated number of customers in the list
     */
    public int add(Customer newCustomer) {

        if (numberOfCustomers == customers.length) {
            // the current array is full, make a new one with more headroom
            Customer[] newCustomerList = new Customer[customers.length+SIZE_INCREMENT];
            for (int i = 0; i < customers.length; i++) {
                newCustomerList[i] = customers[i];
            }
            // we will add the new customer at end!
            newCustomerList[numberOfCustomers] = newCustomer;

            // replace the customer list with the new one
            customers = newCustomerList;
        }
        else {
            customers[numberOfCustomers] = newCustomer;
        }

        // we've added a new customer!
        numberOfCustomers++;

        return numberOfCustomers;
    }

    /**
     * @return the number of customers in this list
     */
    public int getLength() {
        return numberOfCustomers;
    }

    /**
     * @param i the index of the customer to retrieve
     * @return Customer at index <code>i</code> of this list (zero-based).
     */
    public Customer getCustomer(int i) {
        //TODO: Add boundary check of i (0 <= i < numberOfCustomers)
        return customers[i];
    }

    /**
     * Check if a customer with the same number as the one given exists in this list
     * @param customer the customer to check for (will use customer.getNumber() to check against list)
     * @return <code>true</code> if the customer is found. <code>false</code> otherwise.
     */
    public boolean contains(Customer customer) {
        for (int i = 0; i < numberOfCustomers; i++) {
            if (customers[i].getNumber() == customer.getNumber()) {
                return true;
            }
        }
        // if we got here, it means we didn't find the customer
        return false;
    }

}

有了这个实现,writeToFile方法的重写是完全一样的,除了我们使用CustomerList代替List<Customer>

static void writeToFile(CustomerList customers, String filename) throws IOException {
    // set up file for output
    // pw used to write to file
    File outputFile = new File(filename);
    FileOutputStream fos = new FileOutputStream(outputFile);
    PrintWriter pw = new PrintWriter(new OutputStreamWriter(fos));

    writeToStream(customers, pw);

    pw.flush();
    pw.close();
}

也非常相似,writeToStream除了因为我们没有使用Iterator,我们必须手动遍历列表:

static void writeToStream(CustomerList customers, PrintWriter pw) throws IOException {

    for (int i = 0; i < customers.getLength(); i++) {
        pw.println(customers.getCustomer(i).getName());
        pw.println(customers.getCustomer(i).getNumber());
    }
    pw.println(0);
    pw.println(0);

}

类似readFromFile-- 除了列表类型之外几乎相同:

public static CustomerList readFromFile(String filename) throws IOException {
    // set up file for reading
    // br used to read from file
    File inputFile = new File(filename);
    FileInputStream fis = new FileInputStream(inputFile);
    BufferedReader br = new BufferedReader(new InputStreamReader(fis));

    CustomerList customers = readFromStream(br);

    br.close(); // end ReadFile class

    return customers;
}

readFromStream也几乎相同,除了类型(使用的方法与使用的方法具有CustomerList相同的签名List<Customer>

public static CustomerList readFromStream(BufferedReader br) throws IOException {

    CustomerList customerList = new CustomerList();

    // Subtract AND assignment operator, It subtracts right operand from the
    // left operand and assign the result to left operand
    boolean moreCustomers = true;
    while (moreCustomers) {
        try {
            Customer customer = new Customer();
            customer.setName(br.readLine());
            String sCustNo = br.readLine();
            customer.setNumber(Integer.parseInt(sCustNo));
            if (customer.getNumber() == 0) {
                moreCustomers = false;
            }
            else {
                customerList.add(customer);
            }
        }
        catch (NumberFormatException x) {
            // happens if the line is not a number.
            // handle this somehow, e.g. by ignoring, logging, or stopping execution
            // for now, we just stop reading
            moreCustomers = false;
        }
    }

    return customerList;
}

最不同的方法是syncToFile,因为我们没有Set保证没有重复的类型,所以我们每次尝试从文件中插入客户时都必须手动检查:

static void syncToFile(CustomerList customers, String filename) throws IOException {

    // get a list of existing customers
    CustomerList customersInFile = readFromFile(filename);

    // use a set to merge
    CustomerList customersToWrite = new CustomerList();

    // first add current in-memory customers
    for (int i = 0; i < customers.getLength(); i++) {
        customersToWrite.add(customers.getCustomer(i));
    }

    // then add the ones from the file. But skip duplicates
    for (int i = 0; i < customersInFile.getLength(); i++) {
        if (!customersToWrite.contains(customersInFile.getCustomer(i))) {
            customersToWrite.add(customersInFile.getCustomer(i));
        }
    }

    // then save the merged set
    writeToFile(customersToWrite, filename);
}

这里需要注意的是,我们可以add通过一个额外的构造函数来优化操作,CustomerList以获取新的容量,但我至少会留下一些东西让你弄清楚;)

于 2016-03-19T15:14:45.867 回答