我们如何在C#上使用FileMode.Append?

问题描述:

我一直在想办法让我的代码打开一个文件或创建一个(如果我给出的文件名是不存在的)。之后,它将运行一个程序,最终创建一个数组,并且我希望将该数组的内容转换为字符串并附加到我创建并打开的文件中。除了“追加”部分,我已经掌握了一切。它最后说,“对象引用未设置为对象的实例”。你可以请这个启发我吗?帮助将不胜感激。我们如何在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

您可以使用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

请注意,您也可以只使用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

你为什么不使用using语句

using (FileStream fs = new FileStream("inventory.ini", FileMode.OpenOrCreate, FileAccess.Read)) 
    using (StreamReader reader = new StreamReader(fs)) 
    { 
     // do stuff 
    } 

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

你挖自己与例外,一个漂亮的深洞像这样处理。捕捉异常的一个硬性规则是当你处理它时你恢复程序的状态。你没有。特别是,你忘记关闭文件。然后,当您尝试再次打开文件进行写入时,这会出错。不幸的是,该异常消息误导了另一个文件已经打开的进程。不是这样,它是你的进程仍然有文件打开。

有很多针对此故障对策。您应该使用使用语句来确保即使存在异常也会关闭该文件。你需要修正你的EndOfStream测试,它对文本文件不准确,使用while(true)循环,并在ReadLine()返回null时中断。这解决了原来的问题。

但真正的解决方法是不掩饰的不可忽视的真相。允许程序在配置文件被破坏时继续运行,当它没有做到你希望的功能时会产生更多的麻烦。而且你无法分辨,因为你写给控制台的信息是从屏幕上滚动出来的。 非常难诊断。

从此代码中删除try/catch。现在你可以解决真正的问题了。