0

I am trying to save data to a csv file but want to ensure that the data that I am about to save isn't already pressent in the csv file. Because of this I want to read the file first and then save the data.

FileStream writer = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
FileStream reader = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

        using (StreamWriter sw = new StreamWriter(writer))
        {
            if (response.Datapoints.Count != 0)
            {
                foreach (var datapoint in response.Datapoints)
                {
                    sb = new StringBuilder();
                    toBeSaved = new string[] { nameSpace, metric, instanceId, datapoint.Timestamp.ToString()};

                    foreach (string str in toBeSaved)
                    {
                        if (str == toBeSaved.Last())
                        {
                            sb.Append(str);
                        }
                        else
                        {
                            sb.Append(str);
                            sb.Append(",");
                        }
                    }
                    // here I get the error that the "Stream is not Readable"
                    using (StreamReader sr = new StreamReader(reader))
                    {
                        if (sr.ReadLine() != sb.ToString())
                        { // only write the data if it is not already there in the file
                            sw.WriteLine(sb.ToString());
                        }
                    }
                }
BigMan
  • 83
  • 2
  • 12

2 Answers2

2

This using statement will dispose the reader:

  using (StreamReader sr = new StreamReader(reader))

The disposing of the StreamReader will also dispose reader. When you access it the next loop iteration it is disposed, hence the error message.

You can circumvent this by creating a new FileStream reader every loop iteration, or by reusing the StreamReader and disposing it after the loop.

I would use a different approach, that is likely more performant.

Unless your input file is really big, read it completely into memory at the beginning:

 var lines = File.ReadLines();

then before you write to the csv file:

 if(!lines.Contains(sb.ToString())
    sw.WriteLine(sb.ToString());
thumbmunkeys
  • 20,606
  • 8
  • 62
  • 110
  • How can I reuse the StreamReader if that's the better option? – BigMan Sep 15 '14 at 10:07
  • The file will grow as I will write more and more data to it, possibly growing to sizes in the gigabytes. Would it then still be a good idea to read the whole file into memory at the beginning? – BigMan Sep 15 '14 at 11:32
  • @BlackBruceWayne if it's gigabytes, then it would not be a good idea. Unfortunately I can't tell you how to fix your code, as I think there is a conceptual problem with it in the way you try to find the duplicates. – thumbmunkeys Sep 15 '14 at 12:17
1

Assuming you are using .Net 4.5 or later it can be set in StreamReader constructor to leave the stream open:

http://msdn.microsoft.com/en-us/library/gg712952(v=vs.110).aspx

public StreamReader(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen)
user3285954
  • 4,499
  • 2
  • 27
  • 19