开发者

Unable to move file because it's being used by another process -- my program?

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)
            {
            }
        }
    }


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


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://www.emptyloop.com/unlocker/ (don't forget check files for viruses :))


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜