C#: Как Вы сделали бы уникальное имя файла путем добавления числа?

Если честно, я не в восторге от любого из предложенных здесь решений. Я нашел хороший способ использовать TapGestureRecognizer, который, я думаю, доходит до сути вашей проблемы: когда вы нажимаете на что-либо, кроме клавиатуры, отклоняйте клавиатуру.

  1. В viewDidLoad зарегистрируйтесь для получения уведомлений клавиатуры и создайте UITapGestureRecognizer:

    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
    
    [nc addObserver:self selector:@selector(keyboardWillShow:) name:
    UIKeyboardWillShowNotification object:nil];
    
    [nc addObserver:self selector:@selector(keyboardWillHide:) name:
    UIKeyboardWillHideNotification object:nil];
    
    tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
    action:@selector(didTapAnywhere:)];
    
  2. Добавьте отображение клавиатуры / скрыть респонденты. Там вы добавляете и удаляете TapGestureRecognizer в UIView, который должен отпускать клавиатуру при нажатии. Примечание. Нет необходимости добавлять его во все подэлементы или элементы управления.

    -(void) keyboardWillShow:(NSNotification *) note {
        [self.view addGestureRecognizer:tapRecognizer];
    }
    
    -(void) keyboardWillHide:(NSNotification *) note
    {
        [self.view removeGestureRecognizer:tapRecognizer];
    }
    
  3. TapGestureRecognizer вызовет вашу функцию, когда он нажмет, и вы можете отклонить клавиатуру следующим образом:

    -(void)didTapAnywhere: (UITapGestureRecognizer*) recognizer {    
        [textField resignFirstResponder];
    }
    

Хорошая вещь о том, что это решение состоит в том, что оно фильтрует только для отводов, а не для считывания. Поэтому, если у вас есть прокрутка контента над клавиатурой, пролистывание все равно будет прокручиваться и клавиатура будет отображаться. Удалив распознаватель жестов после того, как клавиатура исчезнет, ​​будущие касания на вашем экране обрабатываются нормально.

45
задан Svish 3 July 2009 в 07:11
поделиться

10 ответов

Здесь много хороших советов. В итоге я использовал метод, написанный Марком в , ответ на другой вопрос . Немного переформатировал его и добавил еще один метод, чтобы упростить его использование «извне». Вот результат:

private static string numberPattern = " ({0})";

public static string NextAvailableFilename(string path)
{
    // Short-cut if already available
    if (!File.Exists(path))
        return path;

    // If path has extension then insert the number pattern just before the extension and return next filename
    if (Path.HasExtension(path))
        return GetNextFilename(path.Insert(path.LastIndexOf(Path.GetExtension(path)), numberPattern));

    // Otherwise just append the pattern to the path and return next filename
    return GetNextFilename(path + numberPattern);
}

private 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);
}

Пока тестировалось только частично, но обновлю, если обнаружу какие-либо ошибки. ( Код Марка отлично работает!) Если вы обнаружите какие-либо проблемы с ним, прокомментируйте, отредактируйте или что-то в этом роде :)

30
ответ дан 26 November 2019 в 20:57
поделиться
public FileInfo MakeUnique(string path)
{            
    string dir = Path.GetDirectoryName(path);
    string fileName = Path.GetFileNameWithoutExtension(path);
    string fileExt = Path.GetExtension(path);

    for (int i = 1; ;++i) {
        if (!File.Exists(path))
            return new FileInfo(path);

        path = Path.Combine(dir, fileName + " " + i + fileExt);
    }
}

Очевидно, что это уязвимо для условий гонки, как указано в других ответах.

50
ответ дан 26 November 2019 в 20:57
поделиться

Обратите внимание на методы в классе Path , в частности на Path.GetFileNameWithoutExtension () и Path.GetExtension () .

Вы даже можете найти Path.GetRandomFileName () полезным!

Редактировать:

Раньше я пытался записать файл (с моим желаемое имя), а затем с помощью вышеуказанных функций создать новое имя, если выбрасывается соответствующее IOException , повторение до успешного завершения.

0
ответ дан 26 November 2019 в 20:57
поделиться

Это всего лишь строковая операция; найдите место в строке имени файла, куда вы хотите вставить номер, и воссоздайте новую строку с вставленным номером. Чтобы сделать его пригодным для повторного использования, вы можете найти число в этом месте и преобразовать его в целое число, чтобы его можно было увеличить.

Обратите внимание, что в общем случае это так. создание уникального имени файла небезопасно; существуют очевидные опасности состояния гонки .

В платформе могут быть готовые решения для этого, я плохо разбираюсь в C #, поэтому я не могу здесь помочь.

0
ответ дан 26 November 2019 в 20:57
поделиться

Идея состоит в том, чтобы получить список существующих файлов, проанализировать числа, а затем сделать следующий по величине.

Примечание: это уязвимо для условий гонки, поэтому, если у вас есть несколько потоков, создающих эти файлы, будьте осторожны .

Примечание 2: это не проверено.

public static FileInfo GetNextUniqueFile(string path)
{
    //if the given file doesn't exist, we're done
    if(!File.Exists(path))
        return new FileInfo(path);

    //split the path into parts
    string dirName = Path.GetDirectoryName(path);
    string fileName = Path.GetFileNameWithoutExtension(path);
    string fileExt = Path.GetExtension(path);

    //get the directory
    DirectoryInfo dir = new DirectoryInfo(dir);

    //get the list of existing files for this name and extension
    var existingFiles = dir.GetFiles(Path.ChangeExtension(fileName + " *", fileExt);

    //get the number strings from the existing files
    var NumberStrings = from file in existingFiles
                        select Path.GetFileNameWithoutExtension(file.Name)
                            .Remove(0, fileName.Length /*we remove the space too*/);

    //find the highest existing number
    int highestNumber = 0;

    foreach(var numberString in NumberStrings)
    {
        int tempNum;
        if(Int32.TryParse(numberString, out tempnum) && tempNum > highestNumber)
            highestNumber = tempNum;
    }

    //make the new FileInfo object
    string newFileName = fileName + " " + (highestNumber + 1).ToString();
    newFileName = Path.ChangeExtension(fileName, fileExt);

    return new FileInfo(Path.Combine(dirName, newFileName));
}
1
ответ дан 26 November 2019 в 20:57
поделиться

Вставьте новый GUID в имя файла.

3
ответ дан 26 November 2019 в 20:57
поделиться
/// <summary>
/// Create a unique filename for the given filename
/// </summary>
/// <param name="filename">A full filename, e.g., C:\temp\myfile.tmp</param>
/// <returns>A filename like C:\temp\myfile633822247336197902.tmp</returns>
public string GetUniqueFilename(string filename)
{
    string basename = Path.Combine(Path.GetDirectoryName(filename),
                                   Path.GetFileNameWithoutExtension(filename));
    string uniquefilename = string.Format("{0}{1}{2}",
                                            basename,
                                            DateTime.Now.Ticks,
                                            Path.GetExtension(filename));
    // Thread.Sleep(1); // To really prevent collisions, but usually not needed
    return uniquefilename;
}

Поскольку DateTime.Ticks имеет разрешение 100 наносекунд , коллизии крайне маловероятны. Тем не менее, Thread.Sleep (1) обеспечит это, но я сомневаюсь, что это необходимо

4
ответ дан 26 November 2019 в 20:57
поделиться

Если формат вас не беспокоит, вы можете позвонить:

try{
    string tempFile=System.IO.Path.GetTempFileName();
    string file=System.IO.Path.GetFileName(tempFile);
    //use file
    System.IO.File.Delete(tempFile);
}catch(IOException ioe){
  //handle 
}catch(FileIOPermission fp){
  //handle
}

PS: - Пожалуйста, прочтите больше об этом на msdn перед использованием.

5
ответ дан 26 November 2019 в 20:57
поделиться

Если проверка существования файла слишком сложна, вы всегда можете просто добавить дату и время к имени файла, чтобы сделать его уникальным:

FileName.YYYYMMDD.HHMMSS

Может быть, даже при необходимости добавьте миллисекунды.

12
ответ дан 26 November 2019 в 20:57
поделиться

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

public static class FileInfoExtensions
{
    public static FileInfo MakeUnique(this FileInfo fileInfo)
    {
        if (fileInfo == null)
        {
            throw new ArgumentNullException("fileInfo");
        }

        string newfileName = new FileUtilities().GetNextFileName(fileInfo.FullName);
        return new FileInfo(newfileName);
    }
}

public class FileUtilities
{
    public string GetNextFileName(string fullFileName)
    {
        if (fullFileName == null)
        {
            throw new ArgumentNullException("fullFileName");
        }

        if (!File.Exists(fullFileName))
        {
            return fullFileName;
        }
        string baseFileName = Path.GetFileNameWithoutExtension(fullFileName);
        string ext = Path.GetExtension(fullFileName);

        string filePath = Path.GetDirectoryName(fullFileName);
        var numbersUsed = Directory.GetFiles(filePath, baseFileName + "*" + ext)
            .Select(x => Path.GetFileNameWithoutExtension(x).Substring(baseFileName.Length))
            .Select(x =>
                    {
                        int result;
                        return Int32.TryParse(x, out result) ? result : 0;
                    })
            .Distinct()
            .OrderBy(x => x)
            .ToList();

        var firstGap = numbersUsed
            .Select((x, i) => new { Index = i, Item = x })
            .FirstOrDefault(x => x.Index != x.Item);
        int numberToUse = firstGap != null ? firstGap.Item : numbersUsed.Count;
        return Path.Combine(filePath, baseFileName) + numberToUse + ext;
    }
}    
1
ответ дан 26 November 2019 в 20:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: