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に基づくアプローチ

Collectionsこれは、 APIの使用に基づいて提案された書き直しです。

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

ああ...私はほとんど忘れていました:ファイルとメモリ内リストをマージするために a を使用する魔法は、クラスにメソッドSetを実装することに依存しています。上書きする場合は、 も上書きする必要があります。例えば:equals()Customerequals()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に基づくアプローチ

APIを使用できない場合Collections、2 番目に良い方法は、同じ操作をサポートする独自のコレクション型を作成することですが、配列 (または、それを学習した場合はリンク リスト) によってサポートされます。あなたの場合、それは顧客のリストになります。タイプを呼び出します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 に答える