6

I'm developing a Windows application in VS2005 using C#. In my project, I generate dlls and store them in a directory. The dlls will be named as TestAssembly1, TestAssembly2, TestAssembly3 etc.

So consider if the above three dlls are in the directory. The next time the user uses my project, I need to generate dlls like TestAssembly4, TestAssembly5 etc.

So how can I store the count of the dlls in the folder and increment them when the project is used the next time?

The directory can even contain files other than dlls. So how can I do this?

Sildoreth
  • 1,883
  • 1
  • 25
  • 38
SyncMaster
  • 9,754
  • 34
  • 94
  • 137

3 Answers3

13

Personally I'd use a binary search to find the next assembly...

  • start n=1
  • does TestAssembly1.dll exist? (yes)
  • does TestAssembly2.dll exist? (yes)
  • does TestAssembly4.dll exist? (yes)
  • does TestAssembly8.dll exist? (yes)
  • does TestAssembly16.dll exist? (yes)
  • does TestAssembly32.dll exist? (no)

and no use binary search between 16 and 32:

  • does TestAssembly24.dll exist? (yes)
  • does TestAssembly28.dll exist? (yes)
  • does TestAssembly30.dll exist? (no)
  • does TestAssembly29.dll exist? (yes)

so use TestAssembly30.dll

This avoids the need to keep the count separately, so it'll work even if you delete all the files - and the binary search means you don't have too bad performance.

Untested, but something like below; also note that anything based on file existence is immediately a race condition (although usually a very slim one):

    static string GetNextFilename(string pattern) {
        string tmp = string.Format(pattern, 1);
        if (tmp == pattern) {
            throw new ArgumentException(
                 "The pattern must include an index place-holder", "pattern");
        }
        if (!File.Exists(tmp)) return tmp; // short-circuit if no matches

        int min = 1, max = 2; // min is inclusive, max is exclusive/untested
        while (File.Exists(string.Format(pattern, max))) {
            min = max;
            max *= 2;
        }

        while (max != min + 1) {
            int pivot = (max + min) / 2;
            if (File.Exists(string.Format(pattern, pivot))) {
                min = pivot;
            }
            else {
                max = pivot;
            }
        }
        return string.Format(pattern, max);
    }
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • It depends on the problem domain. Do you need special handling for gaps? Do you expect only a handful of files to exist in the dir under normal situations. (getting a full list of files in a dir is much much cheaper than the same amount of file.exist operations) – Sam Saffron May 26 '09 at 08:21
  • @sambo99 - "getting a full list....is much cheaper"; that depends on the number of files in the directory... – Marc Gravell May 26 '09 at 08:34
  • @sambo99; note that there are only 6 file.Exists tests for the first 32 files. This approach does not require you to get a list of the files at all. – Fredrik Mörk May 26 '09 at 08:37
  • Testing for the existance of lots of files is cheaper than enumerating lots of files? – VVS May 26 '09 at 08:42
  • @David - you only test a *fraction* of the files that might exist - so the above is efficient for dense directories. If you have a sparse directory, then fine: list them all and find the max... – Marc Gravell May 26 '09 at 08:45
  • @Marc, yerp I would expect your approach to be less efficient for less than N files in the sequence and more efficient for more than N files in the sequence. I would need to do benchmarking but I suspect N is around the 10 mark for normal dirs and around the 30 mark for network shares. – Sam Saffron May 26 '09 at 08:46
  • Arguably - for N around 10/30, it is going to be quick either way. I like to optimize to improve the worst case performance, not the best case (which is usually plenty quick without extra work). – Marc Gravell May 26 '09 at 08:49
  • @Svish: Something like "myfile{0}.txt" to generate myfile1.txt, myfiel2.txt, etc – Marc Gravell Jul 03 '09 at 08:39
  • Ah. Of course. Cool! Tested it out now and it works perfectly as far as I can see :D – Svish Jul 03 '09 at 10:21
4

You would just use Directory.GetFiles, passing in a pattern for the files you want to return:

http://msdn.microsoft.com/en-us/library/wz42302f.aspx

string[] files = Directory.GetFiles(@"C:\My Directory\", "TestAssembly*.dll");
samjudson
  • 56,243
  • 7
  • 59
  • 69
2

Instead of lots of checking if a file already exist you can get a list of all assemblies, extract their ID's and return the highest ID + 1:

int nextId = GetNextIdFromFileNames(
               "pathToAssemblies", 
               "TestAssembly*.dll", 
               @"TestAssembly(\d+)\.dll");

[...]

public int GetNextIdFromFileNames(string path, string filePattern, string regexPattern)
{
    // get all the file names
    string[] files = Directory.GetFiles(path, filePattern, SearchOption.TopDirectoryOnly);

    // extract the ID from every file, get the highest ID and return it + 1
    return ExtractIdsFromFileList(files, regexPattern)
           .Max() + 1;
}

private IEnumerable<int> ExtractIdsFromFileList(string[] files, string regexPattern)
{
    Regex regex = new Regex(regexPattern, RegexOptions.IgnoreCase);

    foreach (string file in files)
    {
        Match match = regex.Match(file);
        if (match.Success)
        {
            int value;
            if (int.TryParse(match.Groups[1].Value, out value))
            {
                yield return value;
            }
        }
    }
}
Sabuncu
  • 5,095
  • 5
  • 55
  • 89
VVS
  • 19,405
  • 5
  • 46
  • 65