Я не рекомендовал бы это, так как это не должно быть случайным. Это должно быть уникальным.

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

Как лучше всего создать уникальные имена для файлов, которые будут храниться на жестком диске, чтобы не было двух одинаковых файлов?

 user286474025 мая 2018 г., 22:53
Это зависит от других требований; этот [старый] вопрос был / слишком расплывчат.

Ответы на вопрос(17)

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

Например, если вы передадите егоtest.txt, он попытается создать файлы в следующем порядке:

test.txt
test (2).txt
test (3).txt

и т.д. Вы можете указать максимальное количество попыток или просто оставить его по умолчанию.

Вот полный пример:

class Program
{
    static FileStream CreateFileWithUniqueName(string folder, string fileName, 
        int maxAttempts = 1024)
    {
        // get filename base and extension
        var fileBase = Path.GetFileNameWithoutExtension(fileName);
        var ext = Path.GetExtension(fileName);
        // build hash set of filenames for performance
        var files = new HashSet<string>(Directory.GetFiles(folder));

        for (var index = 0; index < maxAttempts; index++)
        {
            // first try with the original filename, else try incrementally adding an index
            var name = (index == 0)
                ? fileName
                : String.Format("{0} ({1}){2}", fileBase, index, ext);

            // check if exists
            var fullPath = Path.Combine(folder, name);
            if(files.Contains(fullPath))
                continue;

            // try to create the file
            try
            {
                return new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write);
            }
            catch (DirectoryNotFoundException) { throw; }
            catch (DriveNotFoundException) { throw; }
            catch (IOException) 
            {
                // Will occur if another thread created a file with this 
                // name since we created the HashSet. Ignore this and just
                // try with the next filename.
            } 
        }

        throw new Exception("Could not create unique filename in " + maxAttempts + " attempts");
    }

    static void Main(string[] args)
    {
        for (var i = 0; i < 500; i++)
        {
            using (var stream = CreateFileWithUniqueName(@"c:\temp\", "test.txt"))
            {
                Console.WriteLine("Created \"" + stream.Name + "\"");
            }
        }

        Console.ReadKey();
    }
}
 Mike Chamberlain10 апр. 2017 г., 19:54
Может быть, «не страдать от состояния гонки» - это лучший способ выразить это.
 Mike Chamberlain22 мар. 2017 г., 02:02
Сам метод является статическим, поэтому ничего не разделяет, поэтому я считаю, что несколько потоков могут безопасно вводить этот метод одновременно. Возможно, потокобезопасный не совсем правильный термин - я пытаюсь передать, что если другой поток / процесс создает файл с конфликтующим именем во время выполнения, тогда этот метод восстанавливает и пытается следующее доступное имя. Не стесняйтесь редактировать, если вы думаете, что это может быть улучшено.
 Kiquenet21 мар. 2017 г., 16:40
потокобезопасной ? неstatic readonly переменная ниlock ?

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

Guid.NewGuid() создать GUID и использовать его в качестве имени файла (или части имени файла вместе со своей отметкой времени, если хотите).

и он работает нормально. Я надеюсь, что это может помочь вам.

Я начинаю с уникального имени файла, используя отметку времени -

"context_" + DateTime.Now.ToString ("yyyyMMddHHmmssffff")

Код C # -

public static string CreateUniqueFile(string logFilePath, string logFileName, string fileExt)
    {
        try
        {
            int fileNumber = 1;

            //prefix with . if not already provided
            fileExt = (!fileExt.StartsWith(".")) ? "." + fileExt : fileExt;

            //Generate new name
            while (File.Exists(Path.Combine(logFilePath, logFileName + "-" + fileNumber.ToString() + fileExt)))
                fileNumber++;

            //Create empty file, retry until one is created
            while (!CreateNewLogfile(logFilePath, logFileName + "-" + fileNumber.ToString() + fileExt))
                fileNumber++;

            return logFileName + "-" + fileNumber.ToString() + fileExt;
        }
        catch (Exception)
        {
            throw;
        }
    }

    private static bool CreateNewLogfile(string logFilePath, string logFile)
    {
        try
        {
            FileStream fs = new FileStream(Path.Combine(logFilePath, logFile), FileMode.CreateNew);
            fs.Close();
            return true;
        }
        catch (IOException)   //File exists, can not create new
        {
            return false;
        }
        catch (Exception)     //Exception occured
        {
            throw;
        }
    }

начать с имени файла ствола (work.dat1 например)попробуйте создать его с помощью CreateNewесли это работает, у вас есть файл, в противном случае ...смешать текущую дату / время в имени файла (work.2011-01-15T112357.dat например)попробуйте создать файлесли это сработало, у вас есть файл, в противном случае ...Смешайте монотонный счетчик в имени файла (work.2011-01-15T112357.0001.dat например. (Мне не нравятся GUID. Я предпочитаю порядок / предсказуемость.)попробуйте создать файл. Продолжайте увеличивать счетчик и повторять попытки, пока файл не будет создан для вас.

Вот пример класса:

static class DirectoryInfoHelpers
{
    public static FileStream CreateFileWithUniqueName( this DirectoryInfo dir , string rootName )
    {
        FileStream fs = dir.TryCreateFile( rootName ) ; // try the simple name first

        // if that didn't work, try mixing in the date/time
        if ( fs == null )
        {
            string date = DateTime.Now.ToString( "yyyy-MM-ddTHHmmss" ) ;
            string stem = Path.GetFileNameWithoutExtension(rootName) ;
            string ext  = Path.GetExtension(rootName) ?? ".dat" ;

            ext = ext.Substring(1);

            string fn = string.Format( "{0}.{1}.{2}" , stem , date , ext ) ;
            fs = dir.TryCreateFile( fn ) ;

            // if mixing in the date/time didn't work, try a sequential search
            if ( fs == null )
            {
                int seq = 0 ;
                do
                {
                    fn = string.Format( "{0}.{1}.{2:0000}.{3}" , stem , date , ++seq , ext ) ;
                    fs = dir.TryCreateFile( fn ) ;
                } while ( fs == null ) ;
            }

        }

        return fs ;
    }

    private static FileStream TryCreateFile(this DirectoryInfo dir , string fileName )
    {
        FileStream fs = null ;
        try
        {
            string fqn = Path.Combine( dir.FullName , fileName ) ;

            fs = new FileStream( fqn , FileMode.CreateNew , FileAccess.ReadWrite , FileShare.None ) ;
        }
        catch ( Exception )
        {
            fs = null ;
        }
        return fs ;
    }

}

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

Код не идеален (например, нет проверок переданных данных). И алгоритм не идеален (например, если вы заполняете жесткий диск или сталкиваетесь с разрешениями, фактическими ошибками ввода-вывода или другими ошибками файловой системы, это будет зависать в бесконечном цикле).

 Kiquenet21 мар. 2017 г., 16:35
Поточно- ?

екунда, и я думаю, что это решение довольно хорошо в моем сценарии

 Kiquenet21 мар. 2017 г., 16:35
какой-нибудь окончательный исходный код для улучшения вашего ответа?

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

Например:

public string GenerateFileName(string context)
{
    return context + "_" + DateTime.Now.ToString("yyyyMMddHHmmssfff") + "_" + Guid.NewGuid().ToString("N");
}

filename1 = GenerateFileName("MeasurementData");
filename2 = GenerateFileName("Image");

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

Обратите внимание, что ограничение имени файла в Windows составляет 255 символов.

 Laurent W.28 янв. 2014 г., 12:24
Должно бытьGuid.NewGuid().ToString();, Отсутствует скобка. +1 в противном случае
 Timothy Shields09 июн. 2013 г., 05:39
+1 За предложение включить полезную информациюв сочетании с GUID. - Отдельно брать зерно соли: указание даты и времени в имени файла является излишним, когда вы можете простоRight Click > Sort By > Date.
 Mas10 июн. 2013 г., 14:27
Время становится полезным, если вы храните несколько файлов с разными контекстами в одном каталоге. Конечно, генерация имени файла должна быть скорректирована с учетом ваших конкретных потребностей.
 JoshYates198021 окт. 2015 г., 20:17
Это очень гладко. Метка времени и Guid. +1

как показано ниже.

Мы можем использовать DateTime.Now.Ticks и Guid.NewGuid (). ToString () для объединения и создания уникального идентификатора.

По мере добавления DateTime.Now.Ticks мы можем узнать дату и время в секундах, в которые создается уникальный идентификатор.

Пожалуйста, смотрите код.

var ticks = DateTime.Now.Ticks;
var guid = Guid.NewGuid().ToString();
var uniqueSessionId = ticks.ToString() +'-'+ guid; //guid created by combining ticks and guid

var datetime = new DateTime(ticks);//for checking purpose
var datetimenow = DateTime.Now;    //both these date times are different.

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

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

 user286474025 мая 2018 г., 22:30
Тем не мение,потолько что с помощью Guid.NewGuid (и игнорируя этот факт, это не «криптографически случайный», который может быть интересен в некоторых случаях), мы можем утверждать, что с достаточно высокой вероятностью того, что нас не волнует иначе, будет сгенерирован уникальный идентификатор - этонамного, намного более высокая гарантия чем 'клещи', Таким образом, «галочки» не имеют никакого значения / использования здесь, ожидайте, поскольку «вторичные» данные вставлены в имя файла.
 user286474024 мая 2018 г., 18:58
Зачем беспокоиться о «галочках», если есть GUID?
 user286474025 мая 2018 г., 22:52
(FWIW: я только что исправил некоторый код с ошибочным вышеупомянутым утверждением об «уникальном времени» ..)
 user286474025 мая 2018 г., 22:28
Тривиально, что предположение о тиках является недействительным: 1) несколько наблюдателей могут видеть один и тот же «тик» (мыслить потоками / процессами) и 2) один и тот же «тик» может наблюдаться несколько раз одним и тем же наблюдателем, если его запрашивать достаточно быстро.
 Jineesh Uvantavida25 мая 2018 г., 08:12
В любом случае, если вам нужно проверить, когда генерируется uniqueSessionId, вы получите точное время. А также при этом конкретный тик будет встречаться только один раз в жизни.
System.IO.Path.GetRandomFileName()

Path.GetRandomFileName () в MSDN.

 epotter11 янв. 2011 г., 14:57
Вот ссылка на документ MSDN:msdn.microsoft.com/en-us/library/...
 Joey11 янв. 2011 г., 19:12
@RyBolt: Так как вам не нужно сеять себя, вы почти ничего не должны учитывать при использовании этого метода. И я ожидаю, что подавляющее большинство разработчиков не имеют ни малейшего представления о том, как создавать безопасные криптографические системы.

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

 Larry Hipp11 янв. 2011 г., 17:12
@downvoter Есть ли причина для отрицательного голосования? GUID для имени файла, кажется, популярный ответ на этот вопрос.
 Larry Hipp11 янв. 2011 г., 17:19
@XMLforDummies мой ответ был одним из первых. Это может показаться не таким, как сейчас, потому что сейчас показывают только часы. Это повторный ответ, потому что это, вероятно, правильный ответ.
 Jader Dias11 янв. 2011 г., 17:14
Это повторный ответ, и у меня недостаточно репутации, чтобы понизить

автоматически сгенерированное для вас без каких-либо пользовательских методов. Просто используйте следующее сКласс StorageFolder илиКласс StorageFile, Ключ здесь:CreationCollisionOption.GenerateUniqueName а такжеNameCollisionOption.GenerateUniqueName

кСоздайте новый файл с уникальным именем файла:

var myFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("myfile.txt", NameCollisionOption.GenerateUniqueName);

ккопия файл в папку с уникальным именем файла:

var myFile2 = await myFile1.CopyAsync(ApplicationData.Current.LocalFolder, myFile1.Name, NameCollisionOption.GenerateUniqueName);

кпереехать файл с уникальным именем файла в месте назначения:

await myFile.MoveAsync(ApplicationData.Current.LocalFolder, myFile.Name, NameCollisionOption.GenerateUniqueName);

кпереименовать файл с уникальным именем файла в месте назначения:

await myFile.RenameAsync(myFile.Name, NameCollisionOption.GenerateUniqueName);

GetRandomFileName:

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

Пример:

public static string GenerateFileName(string extension="")
{
    return string.Concat(Path.GetRandomFileName().Replace(".", ""),
        (!string.IsNullOrEmpty(extension)) ? (extension.StartsWith(".") ? extension : string.Concat(".", extension)) : "");
}
 Koray25 июн. 2018 г., 10:11
@AshishShukla на самом деле я понятия не имею.MSDN говорит "генерируется криптографически сильная, случайная строка". У меня не было проблем до сих пор. Если уникальность имеет решающее значение, дополнительная проверка может быть хорошей идеей.
 Ashish Shukla22 июн. 2018 г., 11:32
Всегда ли метод GetRandomFileName () генерирует уникальное имя файла каждый раз, как GUID ()?

использование

Path.GetTempFileName()

или используйте новый GUID ().

Path.GetTempFilename () в MSDN.

 epotter11 янв. 2011 г., 14:56
Вот ссылка на документ MSDN:msdn.microsoft.com/en-us/library/...
 Joey11 янв. 2011 г., 19:14
Обратите внимание, чтоGetTempFileName() может создать исключение, если вы создадите много таких файлов, не удаляя их.
 user286474024 мая 2018 г., 19:04
ПРЕДУПРЕЖДЕНИЕ:GetTempFileName будемСоздайте файл. Это также означает, что этовыбирает временный путь, С другой стороны,GetRandomFileName подходит для генерации 8,3имя файла это может быть использовано с другим путем. (Я видел какой-то ужасный код, который использует GetTempFileName с File.Delete просто для использования имени файла в другом месте ...)
 Çağdaş Tekin13 янв. 2011 г., 07:37
«Метод GetTempFileName вызоветIOException если он используется для создания более 65535 файлов без удаления предыдущих временных файлов ", - говорится в статье MSDN.
Решение Вопроса

Идентификаторы GUID.

Например.:

var myUniqueFileName = string.Format(@"{0}.txt", Guid.NewGuid());

или жекороче:

var myUniqueFileName = [email protected]"{Guid.NewGuid()}.txt";

В своих программах я иногда пытаюсь, например, 10 раз, чтобы сгенерировать читаемое имя («Image1.png» .. «Image10.png»), и если это не удается (потому что файл уже существует), я возвращаюсь к GUID.

Обновить:

Недавно я также используюDateTime.Now.Ticks вместо GUID:

var myUniqueFileName = string.Format(@"{0}.txt", DateTime.Now.Ticks);

или же

var myUniqueFileName = [email protected]"{DateTime.Now.Ticks}.txt";

Преимущество для меня состоит в том, что это генерирует более короткое и «выглядящее» имя файла по сравнению с GUID.

Обратите внимание, что в некоторых случаях (например, при генерации большого количества случайных имен за очень короткое время) этомог бы сделать неуникальные значения.

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

 WillMcKill20 февр. 2017 г., 13:15
Мне нравится использовать Ticks, поскольку GUID действительно ужасен. Вы также можете получить хеш Ticks, который уменьшает длину символа в имени файла.DateTime.Now.Ticks.GetHashCode().ToString("x").ToUpper()
 user286474024 мая 2018 г., 18:57
«Тики» предсказуемы и не поточнобезопасны (поскольку одни и те же «тики» могут быть получены из нескольких потоков / процессов). Это делает его не пригодным для генерации временного имени файла. Генерация X..1..N может быть подходящей для задач, стоящих перед пользователем (например, копирование в Проводнике), но сомнительна для работы сервера.

исла. Вы можете увидеть ссылку MSDN:http://msdn.microsoft.com/en-us/library/9b3ta19y.aspx

 Max21 февр. 2014 г., 09:36
Я не рекомендовал бы это, так как это не должно быть случайным. Это должно быть уникальным.

которая генерирует имена файлов, как это делает Windows, добавляя порядковый номер перед расширением файла.

Учитывая желаемый путь к файлуC:\MyDir\MyFile.txtи файл уже существует, он возвращает окончательный путь к файлуC:\MyDir\MyFile_1.txt.

Это называется так:

var desiredPath = @"C:\MyDir\MyFile.txt";
var finalPath = UniqueFileName(desiredPath);

private static string UniqueFileName(string path, int count = 0)
{
    if (count == 0)
    {
        if (!File.Exists(path))
        {
            return path;
        }
    }
    else
    {
        var candidatePath = string.Format(
            @"{0}\{1}_{2}{3}",
            Path.GetDirectoryName(path),
            Path.GetFileNameWithoutExtension(path),
            count,
            Path.GetExtension(path));

        if (!File.Exists(candidatePath))
        {
            return candidatePath;
        }
    }

    count++;
    return UniqueFileName(path, count);
}
 Kiquenet22 мар. 2017 г., 09:55
являетсяsource code потокобезопасной?
 user286474024 мая 2018 г., 19:03
Это не потокобезопасный и не безопасный процесс. Существует условие гонки с проверкой File.Exists и любым (предполагаемым позже) созданием файла. Обычно, когда вызывается дважды подряд без создания файла, он возвращает тот же результат.
Создайте ваше временное имя файла, следуя обычному процессуПроверьте, существует ли имя файлаFalse - сохранить файлTrue - добавить в файл дополнительный символ, возможно, счетчикПерейти к шагу 2
 Mike Chamberlain04 дек. 2012 г., 06:24
Смотрите мой ответ для алгоритма, который является потокобезопасным.
 Jader Dias11 янв. 2011 г., 17:14
Этот алгоритм уязвим для параллелизма

Ваш ответ на вопрос