Эта процедура C # для удаления всех файлов, которые НЕ находятся в массиве, выглядит хорошо? - PullRequest
2 голосов
/ 22 июня 2010

У меня есть БД, которая содержит список путей к файлам. Я хочу создать подпрограмму для очистки папок, удаления файлов в каталогах, если для этого нет записи в db (для временных загрузок ajax-файлов, в случаях, когда пользователь не заполняет форму и т. Д.)

Я думаю что-то вроде этого:

var dbFiles = db.allPaths();
var allFiles = Directory.EnumerateFiles(path);

foreach (var f in allFiles) {
  if (!dbFiles.Contains(f) {
    File.Delete(f);
  }
}

Любой "Gotchas" ждет меня? Сначала подпрограмма будет запускаться раз в неделю, чаще, если временные файлы становятся проблемой. Он будет работать в то время, когда почти нет пользователей, поэтому производительность - хотя и важная - не имеет первостепенного значения.

UPDATE

Ух ты, много хороших ответов. Этот фрагмент кода превращается во что-то «достойное» обмена. ; D Мой код выше был простым, быстрым битом-заполнителем ... но он превратился в твердый код. Спасибо!

Ответы [ 4 ]

8 голосов
/ 22 июня 2010

Выглядит хорошо, но вы можете сделать это проще:

foreach (var file in allFiles.Except(dbFiles))
{
    File.Delete(file);
}

Вы должны убедиться, что пути в точно , хотя и в том же формате.Если в одном списке есть относительные файлы, а в другом - абсолютные файлы, или если в одном используется «/», а в другом - «\», вы в конечном итоге удалите то, чего не ожидаете.

В идеале вы »Сначала я явно канонизирую файлы, но я не вижу хорошего способа получить каноническое имя файла в .NET ...

РЕДАКТИРОВАТЬ: обратите внимание, что Path.GetFullPath делает не канонизировать,Он исправляет косые черты и делает его абсолютным, но не учитывает регистр: «c: / users» становится «c: \ users», а «c: / Users» становится «c: \ Users».

Это может быть исправлено с помощью сравнения строк в вызове Except:

var dbFiles = db.AllPaths().Select(Path.GetFullPath));
var allFiles = Directory.EnumerateFiles(path).Select(Path.GetFullPath));

foreach (var file in allFiles.Except(dbFiles, StringComparer.OrdinalIgnoreCase))
{
    File.Delete(file);
}

Теперь это игнорирует регистр - но в «порядковом» порядке.Я не знаю, что на самом деле делает файловая система Windows с точки зрения чувствительности к регистру.

3 голосов
/ 22 июня 2010

выглядит хорошо для меня; однако я никогда не удалял файлы в C #, только VB. Однако вы можете захотеть добавить это в цикл Try / Catch, так как если файл не может быть удален (только для чтения, используется в данный момент, больше не существует и т. Д.), Он выдаст исключение.

РЕДАКТИРОВАТЬ: Как хранятся пути? Помните, что в C # вам нужно выходить из путей "//" вместо использования "\" IIRC.

РЕДАКТИРОВАТЬ 2: Вычеркните последнее редактирование lol.

1 голос
/ 22 июня 2010

Чтобы объединить все предложения в одно:

// canonicalize paths
var dbFiles = db.allPaths().Select(Path.GetFullPath);
var allFiles = Directory.EnumerateFiles(Path.GetFullPath(path))

foreach (var file in allFiles.Except(dbFiles, StringComparer.OrdinalIgnoreCase))
{
    try {
        File.Delete(file);
    } catch (IOException) {
        // handle exception here
    }
}
1 голос
/ 22 июня 2010

Я думаю, что это хорошо по духу, хотя это было бы ближе к:

List<string> dbFiles = db.allPaths();
string[] allFiles = Directory.GetFiles(path);

foreach (string f in allFiles)
    if (!dbFiles.Contains(f))
        File.Delete(f);
...