簡體   English   中英

如何從 ArrayList 寫入文本文件

[英]How to write to a text file from an ArrayList

我正在嘗試從類的ArrayList中獲取數據並將其寫入文本文件。 它創建臨時文件,但不對它做任何事情。 它會打印我要放入文件的內容,並且不會刪除臨時文件。 我究竟做錯了什么?

try
{
    File temp = new File("temp.txt");
    File file = new File(prop.getProperty("path"));
    BufferedWriter writer = new BufferedWriter(new FileWriter(temp));
    ArrayList<Contact> contacts = gestor.checkData();
                        
    if(temp.createNewFile())
    {
        for(int i = 0; i < contacts.size(); i++)
        {
            writer.write(contacts.get(i).getName());
            writer.write(contacts.get(i).getLastNames());
                                
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
            String date = df.format(contacts.get(i).getBirthday());
                                
            writer.write(date);
            writer.write(contacts.get(i).getEmail());
        }
    writer.close();
    file.delete();
    temp.renameTo(file);
    }
}
catch (IOException e)
{
    e.printStackTrace();
}

checkData()的代碼只返回ArrayList<Contact> contactList

您的代碼存在許多問題:

資源泄漏

new FileWriter這樣的東西是一種資源 資源必須關閉。 因此,你永遠不應該創建資源(你通常在創建資源時就知道:你要么調用new X其中 X 顯然代表資源,要么調用諸如socket.getInputStreamFiles.newBufferedReader類的東西......除非你做對了。只有兩種方法可以做到:

try (FileWriter w = new FileWriter(...)) {
   // use it here
}

或者,如果您需要資源成為您的類的一個字段,那么唯一安全的方法是將您的類變成一個資源:使其implements AutoClosable ,創建一個 close 方法,現在使用該 try 語法的負擔是誰使用你的課。 沒有 try-with-resources * 就沒有辦法安全地做這些事情

字符集混亂

文件是字節。 不是字符。 此外,文件系統不知道“編碼”是什么。 您如何將或就此而言é轉換為字節? 答案取決於字符集編碼。 所有將字節轉換為字符或反之亦然java.nio.file包中的方法的問題在於它們使用“平台默認編碼”。 這是說“有史以來最糟糕的想法”的一種有趣方式,因為這將在您的機器上“工作”並通過所有測試,然后在最糟糕的時刻在生產中失敗。 解決方案是永遠不要依賴平台默認值。 如果您真的打算使用它,請明確說明。 不幸的是,在 java11 之前,FileWriter無法指定 charset 編碼,這使得它成為一個完全無用的類,如果不編寫錯誤代碼,您將無法真正使用它。 所以不要。 我建議你切換到新的文件 API,它默認為 UTF-8(相當合理的默認值),並且可以在一行中完成很多復雜的事情。

沒有換行符

您只需.write所有這些數據。 write 完全按照它所說的去做,並且准確地寫入字符串。 它不再打印任何東西。 具體來說,它不打印任何換行符。 您肯定不打算只將JoeSteel1990-10-01文件中,像這樣一團糟? \n來避免這種情況,或者按照你的意願預先構造整個字符串(使用換行符),然后寫下它。

在意想不到的情況下默默地什么都不做

如果“臨時”文件已經存在,您的代碼將不執行任何操作。 聽起來設計是這是一個奇怪的情況(因為臨時文件在之后被“重命名”)。 作為一般的經驗法則,當您遇到您知道不太可能或看似不可能的情況時,“默默地什么都不做”完全是錯誤的本能。 正確的直覺恰恰相反:盡可能地失敗。 (當然,最好的選擇是考慮奇怪的場景意味着什么並正確處理它,但這並不總是可能的)。 因此,請嘗試:

if (!temp.creatNewFile()) {
    throw new RuntimeException("That is weird - tempfile already exists: " + temp);
}

這是正確的心態:如果發生了奇怪的事情,請盡快炸毀,並提供足夠的細節,以便您知道出了什么問題。 (最可能的“正確”處理方法是刪除臨時文件。該臨時文件的全部意義在於,如果在您輸入此代碼時它仍然存在,則之前的嘗試中途失敗,所以只需刪除失敗操作的產物,它沒有用)。

異常處理。

雖然在示例甚至 IDE 模板中很常見,但您做得不對。 你永遠不應該通過打印一些東西並繼續處理異常。 想一想:如果出現問題,繼續執行代碼要么會導致嚴重的問題(因為您在編寫代碼時肯定沒有考慮到程序中的一個步驟失敗),或者會導致另一個錯誤。 如果所有錯誤都這樣處理,那么就會出現一件事,並且您的日志中會出現 85 個錯誤跟蹤。 那沒用。 如果出現問題而您不知道如何處理,請不要繼續運行 唯一明智的“我不知道如何處理”異常處理是:

catch (IOException e) {
    throw new RuntimeException("unhandled", e);
}

有時比 RuntimeException 更好的異常是可能的(例如 UncheckedIOException 或 ServletException,這取決於情況)。 此外,有時正確的答案是向前throws異常。 請記住, public static void main可以(並且通常應該!)被聲明為throws Exception

把它們放在一起

try {
    Path temp = Paths.get("temp.txt");
    Path file = Paths.get(prop.getProperty("path"));
    ArrayList<Contact> contacts = gestor.checkData();

    try (BufferedWriter writer = Files.newBufferedWriter(temp)) {
      for (Contact contact : contacts) {                        
          writer.write(contact.getName());
          writer.write("\n");
          writer.write(contact.getLastNames());
          writer.write("\n");
          DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
          String date = df.format(contact.getBirthday());
          writer.write(date);
          writer.write("\n");
          writer.write(contact.getEmail());
          writer.write("\n");
      }
    }
    Files.delete(file);
    Files.move(temp, file);
} catch (IOException e) {
    throw new UncheckedIOException(e);
}

以上可能會失敗,但它會失敗告訴你它失敗的確切原因。 例如,它可能會告訴您您嘗試寫入的目錄不存在,或者您沒有寫入權限。 而您的代碼將默默地什么也不做。

*) 對於您的 java 專業人士,當然,您可以手動處理自己的 try/finally 循環。 讓我知道當你這樣做時,有多少 Java 新手曾設法避開雷區中的每一個地雷。 直到你完全過冬,這條經驗法則實際上變成了一條法則:沒有 twr,你就無法安全地做到這一點。 讓我們保持簡單。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM