tags:

views:

397

answers:

11

Hello everyone,

Here is my code which opens an XML file (old.xml), filter invalid characters and write to another XML file (abc.xml). Finally I will load the XML (abc.xml) again. When executing the followling line, there is exception says the xml file is used by another process,

xDoc.Load("C:\\abc.xml");

Does anyone have any ideas what is wrong? Any leaks in my code and why (I am using "using" keyword all the time, confused to see leaks...)?

Here is my whole code, I am using C# + VSTS 2008 under Windows Vista x64.

    // Create an instance of StreamReader to read from a file.
    // The using statement also closes the StreamReader.
    Encoding encoding = Encoding.GetEncoding("utf-8", new EncoderReplacementFallback(String.Empty), new DecoderReplacementFallback(String.Empty));
    using (TextWriter writer = new StreamWriter(new FileStream("C:\\abc.xml", FileMode.Create), Encoding.UTF8))
    {
        using (StreamReader sr = new StreamReader(
            "C:\\old.xml",
            encoding
            ))
        {
            int bufferSize = 10 * 1024 * 1024; //could be anything
            char[] buffer = new char[bufferSize];
            // Read from the file until the end of the file is reached.
            int actualsize = sr.Read(buffer, 0, bufferSize);
            writer.Write(buffer, 0, actualsize);
            while (actualsize > 0)
            {
                actualsize = sr.Read(buffer, 0, bufferSize);
                writer.Write(buffer, 0, actualsize);
            }
        }
    }

    try
    {
        XmlDocument xDoc = new XmlDocument();
        xDoc.Load("C:\\abc.xml");
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }

EDIT1: I have tried to change the size of buffer from 10M to 1M and it works! I am so confused, any ideas?

EDIT2: I find this issue is very easy to reproduce when the input old XML file is very big, like 100M or something. I am suspecting whether it is a .Net known bug? I am going to using tools like ProcessExplorer/ProcessMonitor to see which process locks the file to keep it from being accessed by XmlDocument.Load.

+1  A: 

Your buffer isnt being deallocated, is it?

Visage
I think CLR manages all memory buffers. Confused. Anyway, what is your suggested fix? Could you show your code please?
George2
There is no need (and indeed, no mechanism) to deallocate the buffer; GC will pick it up shortly (probably in GEN0, so very cheap).
Marc Gravell
Just the point, the buffer is to big for the stack, so its packed up onto the large object heap - that is never compactet as long as the process is running.
BeowulfOF
@BeowulfOF, what is your solution, could you show your code please?
George2
@BeowulfOF - a char[] buffer is *never* going to go on the stack...
Marc Gravell
+1  A: 

Code works fine. Just checked.

Arnis L.
Strange, any ideas to check further?
George2
Nope... I guess problem is caused by your workstation. Code works, so - only crystal ball could help me to help you.
Arnis L.
+4  A: 

That works fine for me. Purely a guess, but maybe a virus checker is scanning the file? To investigate, try disabling your virus checker and see if it works (and then re-enable your virus checker).

As an aside, there is one way it can leave the file open: if the StreamReader constructor throws an exception; but then you won't reach the XmlDocument stuff anyway... but consider:

using (FileStream fs = new FileStream("C:\\abc.xml", FileMode.Create))
using (TextWriter writer = new StreamWriter(fs, Encoding.UTF8))
{
   ...
}

Now fs is disposed in the edge-case where new StreamWriter(...) throws. However, I do not believe that this is the problem here.

Marc Gravell
I have tried to change the size of buffer from 10M to 1M and it works! I am so confused, any ideas?
George2
+1  A: 

using will call Dispose, but will Dispose call close on the writing stream? If it does not, the system may still consider the file to be open for writing.

I'd try putting in a close of the writer just before then end of its using block.

Edit: Just tried out the code myself as well. Compiled and ran without the problem your are seeing. Try turning off Virus scanners like some others have mentioned and make sure you don't have a window somewhere with the file open.

crashmstr
Close() is implemented by a call to Dispose() and closing a StreamReader or StreamWriter will also close the underlying stream. So this won't help.
Daniel Brückner
+1  A: 

Have you checked that no other process tries to access the file?

Daniel Brückner
I have tried to change the size of buffer from 10M to 1M and it works! I am so confused, any ideas?
George2
+2  A: 

You running a FileSystemWatcher on the root perhaps?

You can also use ProcessMonitor to see who accesses that file.

leppie
FileSystemWatcher? what do you mean?
George2
The FileSystemWatcher class.
leppie
No, I am not using that class explictly, and I have posted all the code. I have tried to change the size of buffer from 10M to 1M and it works! I am so confused, any ideas?
George2
+2  A: 

The problem is your char[] which seems to be to big. If it is too big, it is located on the large objekt heap, not on the stack. Hence the large object heap is not compacted as long as the software is running, the once allocated space there may not be used again - which looks like a memory leak. Try splitting up your array to smaller chunks.

BeowulfOF
I'll grant that the buffer is oversized, but what has that got to do with the problem statement "there is exception says the xml file is used by another process". The buffer
Marc Gravell
I have tried if I use small buffer size, and my code will work without any issues. Why the oversized buffer will block my file from being closed? I think the error I met originally is the file is not closed?
George2
In which case, +1 to BeowulfOF; it doesn't seem obvious that an oversized buffer should cause this (and indeed, I get no problems locally)... curious. OutOfMemoryException, sure... but file locking? Very odd...
Marc Gravell
The idea that the large object heap has anything to do with this sounds like superstition to me. Large objects are collected along with Gen 2, but this is irrelevant because the buffer does not hold a reference to the file - it's just a char[]. There must be some external factors at play.
Jim Arnold
Maybe OS matters? I am using Windows Vista x64, using .Net 3.5 SP1.
George2
+1  A: 

The fact that it works for some people and not for others makes me think that the file isn't being closed. Close the writer before trying to load the file.

Eyal
If the file wasn't being closed, it wouldn't work for anyone! The code shows that the file is being closed (within the scope of this thread/process at least)
Jim Arnold
+2  A: 

I second Leppie's suggestion to use ProcessMonitor (or equivalent) to see for sure who is locking the file. Anything else is just speculation.

Jim Arnold
+1  A: 

My bet is that you have some Antivirus solution running, which locks the file after it is being closed. To verify, try adding a delay (like, 1 second) before loading the file. If that works, you probably found the cause.

Lucero
A: 

Run Process Explorer

Make sure it's your program locking the file first.

Kai Wang