1

I am going through a loop, for each run I wish to open a txt/csv file and search for a value assigned in the loop. If the value exist in the txt file, I wish to write to it on that very line.

Can this be done? I have been playing around with StreamReader and StreamWriter but never really succeeded in both reading and writing to the same file.

I tried this at first but obviously the StreamReader makes the file "busy" so that the StreamWriter cannot access it.

private void WriteTempTXT()
{

    StreamReader sr = new StreamReader(@tmpfile);
    StreamWriter sw = new StreamWriter(@tmpfile);

}

Is there a way to do this?

user3218338
  • 652
  • 1
  • 8
  • 20

3 Answers3

2

First, it can be done. You can create the FileStream with Read/Write access, and then write directly to the stream. Here is a proof of concept:

using (var v = new StreamWriter(File.Create("a.txt"))) {
    v.WriteLine("1234A67890");
}

FileStream fs = new FileStream("a.txt", FileMode.Open, FileAccess.ReadWrite);
while (fs.ReadByte() != 'A') {} // Dangerous.  Loops until 'A' found, infinite loop if none.
fs.Position--;
fs.WriteByte((byte)'5');
fs.Close();  // contents of a.txt now 1234567890

However, there are a number of fundamental problems with this approach:

  1. Risk of file corruption. If the program crashes (or there is a power outage, etc.), the file can be left in an inconsistent state.
  2. Inability to use StreamReader/StreamWriter consistently. Both store data in an internal buffer, which can become stale if the underlying stream is being written to and read concurrently. You can call DiscardBufferedData, but MSDN notes that "this method slows performance and should be called only when absolutely necessary."
  3. Complexity. Inserting text in-place within the file is a costly operation, requiring all subsequent data to be shifted in memory.

Instead, barring overwhelming considerations (e.g., the file is huge relative to available storage), you may want to consider this approach instead:

  1. Create a new temporary file. (You can use System.IO.Path.GetTempFileName() for this purpose).
  2. Read the existing file into the temporary file, making necessary changes. (Use StreamReader to read from the old file, and StreamWriter to write to the new file.)
  3. Overwrite the existing file with the temporary file.

This approach is conceptually similar, but does not incur the risks and complexity of reading from and writing to the same stream concurrently.

drf
  • 8,461
  • 32
  • 50
1

There are two problems with writing to a line in a CSV file:

  1. Files are not line based. You could only replace a line in a file if the encoded data of the new line is exactly the same number of bytes as the original line.

  2. CSV data is not line based. The line break is used as record separator, but as a value can also contain a line break you can't reliably read a CSV file line by line (unless in the special case that you know for certain that no values will ever contain a new line).

If the encoded data for the new line differs in length from the old line, then you have to rewrite the rest of the file to make room for added bytes or remove unused bytes.

The usual approach is to read the entire file and parse it into records, change the record, and then write the entire file back.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • Doing that 15000 times, what performance aspect are we talking here? – user3218338 May 26 '14 at 13:28
  • I'd disagree with (2), when processing csv-file you can use `ReadLine()` safely. Not sure about different encodings though. – Sinatr May 26 '14 at 13:28
  • @Sinatr: You are mistaken. If you for example try to read the record `1,2,"Hello\r\nworld"`, the `ReadLine` method would give you the partial record `1,2,"Hello`. – Guffa May 26 '14 at 13:30
  • @user3218338: Reading and writing 15000 files will naturally take a long time. If you are changing the same file over and over, then you should naturally read it once, make all changes, and write it back when you are all done with it. – Guffa May 26 '14 at 13:32
  • @Guffa, oh, didn't though about line breaks as a part of content (and seems have problems to read written properly). Then yes, you are right. I replace line breaks in strings with `.Replace("\xd\xa", "\\n")` and then back `.Replace("\\n", "\xd\xa")`. – Sinatr May 26 '14 at 13:36
  • @Sinatr: That works as long as the data doesn't contain `\\n`, then it would be replaced with a line break. – Guffa May 26 '14 at 13:41
  • Yup, but you got the idea of why `ReadLine()` is safe for me =P – Sinatr May 26 '14 at 13:47
0

First You Need To follow Up This Example

and then use the class

string path = Server.MapPath("Twitter Overview Report1.csv"); 
    using (CsvFileReader reader = new CsvFileReader(path))
    {
        CsvRow row = new CsvRow();
        while (reader.ReadRow(row))
        {
            foreach (string s in row)
            {
                string s_row = row[0].ToString();
                s_row.Replace("mahmoude", "Ghandour");
            }
            Console.WriteLine();
        }
    }
    using (CsvFileWriter writer = new CsvFileWriter(path))
    {

    }
Mahmoude Elghandour
  • 2,921
  • 1
  • 22
  • 27