Question

Edit: I've retitled this to an example as the code works as expected.

I am trying to copy a file, get a MD5 hash, then delete the copy. I am doing this to avoid process locks on the original file, which another app writes to. However, I am getting a lock on the file I've copied.

File.Copy(pathSrc, pathDest, true);

String md5Result;
StringBuilder sb = new StringBuilder();
MD5 md5Hasher = MD5.Create();

using (FileStream fs = File.OpenRead(pathDest))
{
    foreach(Byte b in md5Hasher.ComputeHash(fs))
        sb.Append(b.ToString("x2").ToLower());
}

md5Result = sb.ToString();

File.Delete(pathDest);

I am then getting a 'process cannot access the file' exception on File.Delete()'.

I would expect that with the using statement, the filestream would be closed nicely. I have also tried declaring the filestream separately, removing using, and putting fs.Close() and fs.Dispose() after the read.

After this, I commented out the actually md5 computation, and the code excutes, with the file being deleted, so it looks like it's something to do with ComputeHash(fs).

Was it helpful?

Solution

I took your code put it in a console app and ran it with no errors, got the hash and the test file is deleted at the end of execution? I just used the .pdb from my test app as the file.

What version of .NET are you running?

I am putting the code that I have that works here, and if you put this in a console app in VS2008 .NET 3.5 sp1 it runs with no errors (at least for me).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace lockTest
{
    class Program
    {
        static void Main(string[] args)
        {
            string hash = GetHash("lockTest.pdb");

            Console.WriteLine("Hash: {0}", hash);

            Console.ReadKey();
        }

        public static string GetHash(string pathSrc)
        {
            string pathDest = "copy_" + pathSrc;

            File.Copy(pathSrc, pathDest, true);

            String md5Result;
            StringBuilder sb = new StringBuilder();
            MD5 md5Hasher = MD5.Create();

            using (FileStream fs = File.OpenRead(pathDest))
            {
                foreach (Byte b in md5Hasher.ComputeHash(fs))
                    sb.Append(b.ToString("x2").ToLower());
            }

            md5Result = sb.ToString();

            File.Delete(pathDest);

            return md5Result;
        }
    }
}

OTHER TIPS

Import the name space

using System.Security.Cryptography;

Here is the function that returns you md5 hash code. You need to pass the string as parameter.

public static string GetMd5Hash(string input)
{
        MD5 md5Hash = MD5.Create();
        // Convert the input string to a byte array and compute the hash.
        byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

        // Create a new Stringbuilder to collect the bytes
        // and create a string.
        StringBuilder sBuilder = new StringBuilder();

        // Loop through each byte of the hashed data 
        // and format each one as a hexadecimal string.
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("x2"));
        }

        // Return the hexadecimal string.
        return sBuilder.ToString();
}

Did you try wrapping your MD5 object in a using() too? From the docs, MD5 is Disposable. That might make it let go of the file.

md5hasher.Clear() after your loop might do the trick.

Have you tried setting md5Hasher to null before deleting the file? It probably has a handle still attached to the FileStream (memory leak perhaps).

Why not open the file with FileShare.ReadWrite?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top