4

I have a strange problem. So my code follows as following.

  1. The exe takes some data from the user

  2. Call a web service to write(and create CSV for the data) the file at perticular network location(say \some-server\some-directory). Although this web service is hosted at the same location where this folder is (i.e i can also change it to be c:\some-directory). It then returns after writing the file

  3. the exe checks for the file to exists, if the file exists then further processing else quite with error.

The problem I am having is at step 3. When I try to read the file immediately after it has been written, I always get file not found exception(but the file there is present). I do not get this exception when I am debugging (because then I am putting a delay by debugging the code) or when Thread.Sleep(3000) before reading the file.

This is really strange because I close the StreamWriter before I return the call to exe. Now according to the documention, close should force the flush of the stream. This is also not related to the size of the file. Also I am not doing Async thread calls for writing and reading the file. They are running in same thread serially one after another(only writing is done by a web service and reading is done by exe. Still the call is serial)

I do not know, but it feels like there is some time difference between the file actually gets written on the disk and when you do Close(). However this baffling because this is not at all related to size. This happens for all file size. I have tried this with file with 10, 50, 100,200 lines of data.

Another thing which I suspected was since I was writing this file to a network location, it could be windows is optimizing the call by writing first to cache and then to network location. So I went ahead and changed the code to write it on drive(i.e use c:\some-directory), rather than network location. But it also resulted in same error.

There is no error in code(for reading and writing). As explained earlier, by putting a delay, it starts working fine. Some other useful information

  1. The exe is .Net Framework 3.5
  2. Windows Server 2008(64 bit, 4 GB Ram)

Edit 1 File.AppendAllText() is not correct solution, as it creates a new file, if it does not exits

Edit 2 code for writing

using (FileStream fs = new FileStream(outFileName, FileMode.Create))
        {
            using (StreamWriter writer = new StreamWriter(fs, Encoding.Unicode))
            {
                writer.WriteLine(someString)
            }
        }

code for reading

  StreamReader rdr = new StreamReader(File.OpenRead(CsvFilePath));
  string header = rdr.ReadLine();
  rdr.Close();

Edit 3 used textwriter, same error

  using (TextWriter writer = File.CreateText(outFileName))
    {
    }

Edit 3 Finally as suggested by some users, I am doing a check for the file in while loop for certain number of times before I throw the exception of file not found.

int i = 1;
while (i++ < 10)
{
   bool fileExists = File.Exists(CsvFilePath);
   if (!fileExists)
     System.Threading.Thread.Sleep(500);
   else
     break;
}
Anand
  • 14,545
  • 8
  • 32
  • 44
  • 1
    Just an experiment: have you tried appending instead of reading (say, `File.AppendAllText`). Will it silently update the file or give an error (something connected with files conflicts). – Artur Udod Jul 18 '13 at 09:54
  • Is the the "Enable write caching on the disk" feature for your hard disk turned on? [HOW TO: Manually Turn Disk Write Caching On or Off](http://support.microsoft.com/kb/324805). – Alex Filipovici Jul 18 '13 at 09:57
  • It ran fine in first go by using File.AppendAllText..Lemme try and test it with serveral times to prove this works. Bit strange though ? – Anand Jul 18 '13 at 09:59
  • Also checking this disk cache thing... – Anand Jul 18 '13 at 10:00
  • related: http://stackoverflow.com/questions/6350224/does-filestream-dispose-close-the-file-immediately – James Jul 18 '13 at 10:03
  • Yes, it's strange cause the OS should be able to know that the file is currently cached and not yet on disk. – C4stor Jul 18 '13 at 10:03
  • I can not check Caching on Disk is turned on or not because of policy issue. Meanwhile i tested this with File.AppendAllText() and it worked fine @ArturUdod - Any explanation for this ??? – Anand Jul 18 '13 at 10:09
  • @ArturUdod - If you could write your answer as answer and not as comment then I could accept your answer. I can def. say it working when Before I reading the file, I do a File.AppendAllText(path, ""). Just append nothing – Anand Jul 18 '13 at 10:11
  • I also tried File.Exists() instead of File.AppendAllText() and exists also fails ...Now its really strange – Anand Jul 18 '13 at 10:23
  • File.AppendAllText() is not correct as it creates the file if it does not exists – Anand Jul 18 '13 at 10:47
  • @Anand, that is why I suggested to test this, cause in case when system doesn't detect the existing file it will try to create new one, thus, the original one won't be created ( some error about conflicts) – Artur Udod Jul 18 '13 at 11:17
  • Another guess: try using `File.WiteAllText` instead of `StreamWriter` – Artur Udod Jul 18 '13 at 11:19
  • Create a smaller program that reproduces the problem. `using (File.Create("foo.txt"); using (new StreamReader("foo.txt"));` does not fail for me. – CodeCaster Jul 18 '13 at 11:55
  • Yes, I know. this has worked for me in so many times before. this time its failing. As I have said earlier, I am using StreamWriter. So when I close it, i give the handle back to OS to write everything on disk. Now it could be in my case, the OS is trying to be smart to optimize the process of writing the file to disk and hence not writing immediately to the disk...Its just a guess, do not know the implementation in Windows Server – Anand Jul 18 '13 at 12:15
  • Are you using any other caching mechanism on the web server, is you web service using caching? – lex87 Jul 18 '13 at 12:31
  • No. Its and asmx service and by default since all soap request are post they should not be cached. The task is completed and it writes the file to disk but when I try to run it immediately it fails. Adding a delay of a second solves the issue. Look for my update – Anand Jul 18 '13 at 12:58

3 Answers3

1

So you are writing a stream to a file, then reading the file back to a stream? Do you need to write the file then post process it, or can you not just use the source stream directly?

If you need the file, I would use a loop that keeps checking if the file exists every second until it appears (or a silly amount of time has passed) - the writer would give you an error if you couldn't write the file, so you know it will turn up eventually.

  • It would kind of complex because writing is done by web service. I am not sure weather we can return FileStream from web service ...it does not implement Serializable class. – Anand Jul 18 '13 at 12:09
  • GUess only feasilble solution is to loop and then wait for some time in the loop. In this way performance will never be worst than thread.sleep(n) n seconds. So if I do 10 trys to read the file in a while loop. Each loop would wait for n/10 seconds – Anand Jul 18 '13 at 12:11
  • Hmmm, this is a really odd issue. So `File.WriteAllText` didn't work? Doesn't make sense. But again, you were using Windows Server. I think it might have something to do with file system setting. Do paste the problem on MSDN Forums, someone will give a better explanation there. – Chibueze Opata Jul 18 '13 at 16:08
0

Since you're writing over a network, most optimal solution would be to save your file in the local system first, then copy it to network location. This way you can avoid network connection problems. And as well have a backup in case of network failure.

Based on your update, Try this instead:

File.WriteAllText(outFileName, someString);
header = null;
using(StreamReader reader = new StreamReader(CsvFilePath)) {
    header = reader.ReadLine();
}
Chibueze Opata
  • 9,856
  • 7
  • 42
  • 65
  • yes, I tried that also. Instead of writing to network location writing to local disk directly and then reading it from there. But it fails. The reason I can think is, when we call close(), we give the control to OS to write the stuff to disk. Now OS can optimize this and write the file to disk when ever it feels convenient. I think immediately reading the file will give error, so better wait for some time in loop to check for the file exists – Anand Jul 18 '13 at 11:00
  • Since you're using threads, you should perform a manual close and dispose on the StreamWriter. Have you tried using `TextWriter` or `File.WriteAllText`? – Chibueze Opata Jul 18 '13 at 11:06
  • I am not using threads. Its called serially one after another. I have called Close() method before I try to read the the file. I am using StreamWriter(which is derived from TextWriter) – Anand Jul 18 '13 at 11:15
  • That's why I suggested using `TextWriter` or `File.Write` since they are more direct and don't deal with the GC in the same way `StreamWriter` does. It would also be helpful if you can post the code. – Chibueze Opata Jul 18 '13 at 11:18
0

Have you tried to read after disposing the writer FileStream?

Like this:

using (FileStream fs = new FileStream(outFileName, FileMode.Create))
{
    using (StreamWriter writer = new StreamWriter(fs, Encoding.Unicode))
    {
        writer.WriteLine(someString)
    }
}

using (StreamReader rdr = new StreamReader(File.OpenRead(CsvFilePath)))
{
    string header = rdr.ReadLine();
}
Akira Yamamoto
  • 4,685
  • 4
  • 42
  • 43
  • yes exactly the same. Nothing worked. Wrote code using "using". Called flush, called Close(), used textwriter everything. One important thing is Read is workable, if I put in some delay before I try to read it....GUess that would have failed if I have not called dispose/close – Anand Jul 18 '13 at 13:06