2013-05-04 217 views
0

我一直在想辦法讓我的代碼打開一個文件或創建一個(如果我給出的文件名是不存在的)。之後,它將運行一個程序,最終創建一個數組,並且我希望將該數組的內容轉換爲字符串並附加到我創建並打開的文件中。除了「追加」部分,我已經掌握了一切。它最後說,「對象引用未設置爲對象的實例」。你可以請這個啓發我嗎?幫助將不勝感激。我們如何在C#上使用FileMode.Append?

 try 
     { 
      FileStream fs = new FileStream("inventory.ini", FileMode.OpenOrCreate, FileAccess.Read); 
      StreamReader reader = new StreamReader(fs); 

      while (!reader.EndOfStream) 
      { 
       string line = reader.ReadLine(); 
       string[] data = line.Split('|'); 
       int code = int.Parse(data[0]); 
       string name = data[1]; 
       double price = double.Parse(data[2]); 

       Item item = new Item(code, name, price); 
       app.array[inventoryCount++] = item;  
      } 

      reader.Close(); 
      fs.Close(); 
     } 

     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
     } 

     app.Run(); 

     try 
     { 
      FileStream fs = new FileStream("inventory.ini", FileMode.Append, FileAccess.Write); 
      StreamWriter writer = new StreamWriter(fs); 

      foreach (Item item in app.array) 
      { 
       writer.WriteLine(item.Code + "|" + item.Name + "|" + item.Price); 
      } 

      writer.Close(); 
      fs.Close(); 
     } 

     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 
     } 
     Console.ReadLine(); 
    } 
+0

哪一行發生異常? – 2013-05-04 17:07:59

+0

它發生在app.Run()之後。它說該文件不能被訪問,因爲它正被另一個進程使用。 – joseminicario 2013-05-04 17:22:14

+0

但是在你說的問題是「對象引用未設置爲對象的實例」。 – 2013-05-04 17:27:16

回答

2

您可以使用StreamWriter另一個構造,即允許附加,再這樣寫:

StreamWriter writer = new StreamWriter("inventory.ini", true); 

我從來沒有使用過的FileStream我的應用程序,但StreamWriter的已經相當可靠。您也可以切換到Using聲明,那麼您不需要Close()

此外,我建議切換到lists,那麼你將永遠有app.array(這順便說一句需要一個更好的名字)內需要的物品的確切數量。所以這個:

app.array[inventoryCount++] = item; 

會變成這樣的事情:

​​

除了內存管理頭痛緩解,不再需要inventoryCount變量,因爲你可以從list.Count得到這個值;

這裏的一般方法是儘量減少你需要編寫,對於相同數量的功能代碼量。那麼你就沒有潛在的錯誤潛藏。

+0

@JeffMercado:不確定多個AppendText會影響文件打開狀態。我有一種感覺,它可能最終會被多次打開和關閉,這可能不是預期的行爲。有時溪流很好。 – Neolisk 2013-05-04 17:09:47

+1

Bah,我毀了我的評論。無論如何,我的觀點是,你應該在'File'類中使用工廠方法而不是使用這些構造方法。它對它正在做的事情有更明確的意圖。 – 2013-05-04 17:11:41

+0

當我使用新的構造函數時,它發生了一些變化。該錯誤現在說該文件不能被訪問,因爲它正在被另一個進程使用。 – joseminicario 2013-05-04 17:21:25

0

請注意,您也可以只使用File.AppendText()追加模式打開一個StreamWriter

您還應該使用using而不是.Close()關閉流 - 那麼它會工作,即使發生異常。

所以,你的代碼看起來會像這樣:

try 
{ 
    using (var writer = File.AppendText("inventory.ini")) 
    { 
     foreach (Item item in app.array) 
     { 
      if (item != null) 
       writer.WriteLine(item.Code + "|" + item.Name + "|" + item.Price); 
     } 
    } 
} 

catch (Exception e) 
{ 
    Console.WriteLine(e.Message); 
} 
+0

我試着複製你的代碼,它仍然返回「對象引用未設置爲對象的實例。」謝謝,不過。 – joseminicario 2013-05-05 02:21:38

+2

@joseminicario我認爲你有一個不同的錯誤,你使'app.array'大於你讀入它的項目數量,所以當你試圖寫出它們時,你會在數組中得到一個'null'項目你達到了你閱讀的最後一個項目。我已經修改了上面的代碼以防止出現這種情況(請參閱'if(item!= null)') - 是否有幫助? – 2013-05-05 08:54:16

+0

@joseminicario:對,雖然我相信解決方案可能比這更復雜。無論如何,我建議你使用列表來代替。沒有內存管理 - 沒有頭痛。 – Neolisk 2013-05-05 11:47:44

0

你爲什麼不使用using語句

using (FileStream fs = new FileStream("inventory.ini", FileMode.OpenOrCreate, FileAccess.Read)) 
    using (StreamReader reader = new StreamReader(fs)) 
    { 
     // do stuff 
    } 
2
catch (Exception e) 
    { 
     Console.WriteLine(e.Message); 
    } 

你挖自己與例外,一個漂亮的深洞像這樣處理。捕捉異常的一個硬性規則是當你處理它時你恢復程序的狀態。你沒有。特別是,你忘記關閉文件。然後,當您嘗試再次打開文件進行寫入時,這會出錯。不幸的是,該異常消息誤導了另一個文件已經打開的進程。不是這樣,它是你的進程仍然有文件打開。

有很多針對此故障對策。您應該使用使用語句來確保即使存在異常也會關閉該文件。你需要修正你的EndOfStream測試,它對文本文件不準確,使用while(true)循環,並在ReadLine()返回null時中斷。這解決了原來的問題。

但真正的解決方法是不掩飾的不可忽視的真相。允許程序在配置文件被破壞時繼續運行,當它沒有做到你希望的功能時會產生更多的麻煩。而且你無法分辨,因爲你寫給控制檯的信息是從屏幕上滾動出來的。 非常難診斷。

從此代碼中刪除try/catch。現在你可以解決真正的問題了。