tags:

views:

282

answers:

3

My program is unable to File.Move or File.Delete a file because it is being used "by another process", but it's actually my own program that is using it.

I use Directory.GetFiles to initially get the file paths, and from there, I process the files by simply looking at their names and processing information that way. Consequently all I'm doing is working with the strings themselves, right? Afterwards, I try to move the files to a "Handled" directory. Nearly all of them will usually move, but from time to time, they simply won't because they're being used by my program.

Why is it that most of them move but one or two stick around? Is there anything I can do to try freeing up the file? There's no streams to close.

Edit Here's some code:

public object[] UnzipFiles(string[] zipFiles)
    {
        ArrayList al = new ArrayList(); //not sure of proper array size, so using arraylist
        string[] files = null;

        for (int a = 0; a < zipFiles.Length; a++)
        {
            string destination = settings.GetTorrentSaveFolder() + @"\[CSL]--Temp\" + Path.GetFileNameWithoutExtension(zipFiles[a]) + @"\";
            try
            {
                fz.ExtractZip(zipFiles[a], destination, ".torrent");

                files = Directory.GetFiles(destination, 
                    "*.torrent", SearchOption.AllDirectories);

                for (int b = 0; b < files.Length; b++)
                    al.Add(files[b]);
            }

            catch(Exception e)
            {}
        }

        try
        {
            return al.ToArray(); //return all files of all zips
        }
        catch (Exception e)
        {
            return null;
        }
    }

This is called from:

try
                {
                    object[] rawFiles = directory.UnzipFiles(zipFiles);
                    string[] files = Array.ConvertAll<object, string>(rawFiles, Convert.ToString);
                    if (files != null)
                    {
                        torrents = builder.Build(files);
                        xml.AddTorrents(torrents);
                        directory.MoveProcessedFiles(xml);
                        directory.MoveProcessedZipFiles();
                    }
                }
                catch (Exception e)
                { }

Therefore, the builder builds objects of class Torrent. Then I add the objects of class Torrent into a xml file, which stores information about it, and then I try to move the processed files which uses the xml file as reference about where each file is.

Despite it all working fine for most of the files, I'll get an IOException thrown about it being used by another process eventually here:

public void MoveProcessedZipFiles()
    {
        string[] zipFiles = Directory.GetFiles(settings.GetTorrentSaveFolder(), "*.zip", SearchOption.TopDirectoryOnly);

        if (!Directory.Exists(settings.GetTorrentSaveFolder() + @"\[CSL] -- Processed Zips"))
            Directory.CreateDirectory(settings.GetTorrentSaveFolder() + @"\[CSL] -- Processed Zips");

        for (int a = 0; a < zipFiles.Length; a++)
        {
            try
            {
                File.Move(zipFiles[a], settings.GetTorrentSaveFolder() + @"\[CSL] -- Processed Zips\" + zipFiles[a].Substring(zipFiles[a].LastIndexOf('\\') + 1));
            }
            catch (Exception e)
            {
            }
        }
    }
A: 

What this mean: "there is no streams to close"? You mean that you do not use streams or that you close them?
I believe that you nevertheless have some opened stream.
Do you have some static classes that uses this files?
1. Try to write simple application that will only parse move and delete the files, see if this will works.
2. Write here some pieces of code that works with your files.
3. Try to use unlocker to be sure twice that you have not any other thing that uses those files: http://ccollomb.free.fr/unlocker/ (don't forget check files for viruses :))

rodnower
I think I may have a static class that uses the file! I'll check it out! I mean, I don't open a `FileStream` to handle the files. I have made a simple application in trying to reproduce the issue that pulled the file paths into a string array, did small operations on each string in the array, and then moved all the file paths from the string array. This worked fine, which points to something else in my processing like Darin pointed out
joslinm
+2  A: 

Based on your comments, this really smells like a handle leak. Then, looking at your code, the fz.ExtractZip(...) looks like the best candidate to be using file handles, and hence be leaking them.

Is the type of fz part of your code, or a third party library? If it's within your code, make sure it closes all its handles (the safest way is via using or try-finally blocks). If it's part of a third party library, check the documentation and see if it requires any kind of cleanup. It's quite possible that it implements IDisposable; in such case put its usage within a using block or ensure it's properly disposed.

The line catch(Exception e) {} is horribly bad practice. You should only get rid of exceptions this way when you know exactly what exception may be thrown and why do you want to ignore it. If an exception your program can't handle happens, it's better for it to crash with a descriptive error message and valuable debug information (eg: exception type, stack trace, etc), than to ignore the issue and continue as if nothing had gone wrong, because an exception means that something has definitely gone wrong.

Long story short, the quickest approach to debug your program would be to:

  1. replace your generic catchers with finally blocks
  2. add/move any relevant cleanup code to the finally blocks
  3. pay attention to any exception you get: where was it thrown form? what kind of exception is it? what the documentation or code comments say about the method throwing it? and so on.
  4. Either
    4.1. If the type of fz is part of your code, look for leaks there.
    4.2. If it's part of a third party library, review the documentation (and consider getting support from the author).

Hope this helps

herenvardo
Yes, the FastZip library is a third party, and in my code is denoted by fz.Thanks for the help and constructive criticism. I did have breakpoints there, and was usually holding the try catch so I can see where it went wrong and see if I can trace it back.I've considered the FastZip library, but the problem is, that's when my program handles zips. Unfortunately it also handles lone files, and I run into the same exact problem. I've tried both.
joslinm
I've just realized that I use `Path.GetFileName` while processing the files, and this creates a file handle. Though I've tried reproducing this, and have been unsuccessful so far..
joslinm
A: 

Class Path was handling multiple files to get me their filenames. Despite being unsuccessful in reproducing the same issue, forcing a garbage collect using GC.Collect at the end of the "processing" phase of my program has been successful in fixing the issue.

Thanks again all who helped. I learned a lot.

joslinm
Don't try to "fix" such problems with a `GC.Collect` (see e.g. http://henbo.spaces.live.com/blog/cns!2E073207A544E12!273.entry). It might work ok for your app, but you need to learn to manage resources correctly. And pelase don't let these "everything you do is wrong" comments stop you asking questions ;)
peterchen
Haha, I'll try not to! :D Not to pester you, and I don't think qualifies as a brand new question.. but can you link me to any good resources on how to handle resources properly? I've tried looking around and most of the admittedly boggle me. I've looked into subclassing IDisposable, but then got subsequently confused about how/what to use a `private IntPtr handle;`. My confusion stems from this line of thought:1.)I'm just trying to find out the filename using `Path`. 2.)How can I use `Path` with `IntPtr`?Plenty of other things confuse me.. so a good tutorial would be helpful :]
joslinm