C #에서 고유 한 파일 이름을 생성하는 방법


131

하드 드라이브에 저장할 파일의 고유 이름을 생성하는 알고리즘을 구현했습니다. 내가 추가하고 있습니다 DateTime: Hours, Minutes, Second and Milliseconds 하지만 한 번에 여러 파일을 업로드하기 때문에 여전히 중복 된 파일 이름을 생성합니다.

파일이 하드 드라이브에 저장되도록 고유 한 이름을 생성하여 2 개의 파일이 동일하지 않도록하는 가장 좋은 솔루션은 무엇입니까?


다른 요구 사항에 따라 다릅니다. 이 [오래된] 질문은 너무 모호했습니다.
user2864740

답변:


240

가독성이 중요하지 않으면 GUID를 사용하십시오 .

예 :

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

또는 더 짧은 :

var myUniqueFileName = $@"{Guid.NewGuid()}.txt";

내 프로그램에서 읽을 수있는 이름 ( "Image1.png"… "Image10.png")을 생성하기 위해 예를 들어 10 번 시도하는 경우가 있는데 (파일이 이미 있기 때문에) 실패하면 GUID로 돌아갑니다.

최신 정보:

최근 DateTime.Now.Ticks에는 GUID 대신 사용 했습니다.

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

또는

var myUniqueFileName = $@"{DateTime.Now.Ticks}.txt";

나에게 이점은 이것이 GUID에 비해 더 짧고 "더욱보기 좋은"파일 이름을 생성한다는 것입니다.

경우에 따라 (예 : 매우 짧은 시간에 많은 임의의 이름을 생성 할 때) 고유하지 않은 값을 만들 수 있습니다 .

다른 컴퓨터로 파일을 전송할 때에도 파일 이름이 고유한지 확인하려면 GUID를 고수하십시오.


7
나는 진드기를 GUID로 사용하는 것이 정말 추악합니다. 파일 이름의 문자 길이를 줄이는 Ticks 해시를 얻을 수도 있습니다. DateTime.Now.Ticks.GetHashCode().ToString("x").ToUpper()
WillMcKill

4
"틱"은 예측 가능하며 스레드로부터 안전하지 않습니다 (여러 스레드 / 프로세스에서 동일한 '틱'을 얻을 수 있으므로). 이것은 임시 파일 이름 생성에 적합하지 않습니다. X..1..N을 생성하는 것은 사용자가 직면 한 작업 (예 : Explorer에서 복사)에 적합 할 수 있지만 서버 작업에는 모호합니다.
user2864740

90

사용하다

Path.GetTempFileName()

또는 새로운 GUID ()를 사용하십시오.

MSDN의 Path.GetTempFilename () .


MSDN 문서에 대한 링크는 다음과 같습니다. msdn.microsoft.com/en-us/library/…
epotter

3
그러나 GetTempFileName()그러한 파일을 삭제하지 않고 많은 파일을 작성하면 예외가 발생할 수 있습니다.
Joey

21
" 이전 임시 파일을 삭제하지 않고 65535 개 이상의 파일을 만드는 데 사용되는 경우 GetTempFileName 메서드는 IOException을 발생시킵니다." MSDN 기사를 말합니다.
Çağdaş Tekin

1
경고 : 파일 GetTempFileName생성 합니다. 또한 임시 경로 위치를 선택합니다 . 반면에 다른 경로와 함께 사용할 수 GetRandomFileName있는 8.3 파일 이름 을 생성하는 데 적합 합니다. (다른 곳에 파일 이름을 사용하기 위해 File.Delete와 함께 GetTempFileName을 사용하는 일부 무시한 코드를 보았습니다.)
user2864740


54

파일 이름의 가독성이 중요하지 않은 경우 많은 사람들이 제안한 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");

이렇게하면 파일 이름으로 정렬하면 컨텍스트 문자열로 파일을 자동으로 그룹화하고 타임 스탬프로 정렬합니다.

창의 파일 이름 제한은 255 자입니다.


1
+1 유용한 정보를 GUID 와 결합 하여 제안합니다 . -소금 한 덩어리와 함께 따로 따로 따로 : 파일 이름에 날짜와 시간을 포함하는 것은 당신이 할 수있을 때 중복됩니다 Right Click > Sort By > Date.
Timothy Shields 2012 년

1
동일한 디렉토리에 다른 컨텍스트를 가진 많은 파일을 저장하는 경우 시간이 유용합니다. 물론 파일 이름 생성은 특정 요구에 따라 조정해야합니다.
Mas

이어야 Guid.NewGuid().ToString();합니다. 괄호가 없습니다. +1
Laurent W.

이것은 매우 매끄 럽습니다. 타임 스탬프와 길드. +1
JoshYates1980

이 솔루션을 좋아합니다 +1, fileName에 추가하는 두 번째 매개 변수 문자열 확장명을 추가했습니다. 컨텍스트의 개념을 추가로 지원하고 필요한 경우 더블 클릭으로 기본 응용 프로그램으로 파일을 쉽게 열 수 있습니다.
shelbypereira

23

다음은 제공된 원본을 기준으로 읽을 수있는 고유 한 파일 이름을 반환하는 알고리즘입니다. 원본 파일이 있으면 존재하지 않는 파일을 찾을 때까지 파일 이름에 색인을 추가하려고합니다. 충돌을 확인하기 위해 기존 파일 이름을 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();
    }
}

스레드 안전 ? 없는static readonly 변수lock?
Kiquenet

메소드 자체는 정적이므로 아무 것도 공유하지 않으므로 여러 스레드 가이 메소드를 동시에 안전하게 입력 할 수 있다고 생각합니다. 아마도 스레드 안전은 올바른 용어가 아닙니다. 다른 스레드 / 프로세스가 실행 중에 이름이 충돌하는 파일을 만드는 경우이 방법을 복구하고 사용 가능한 다음 이름을 시도한다는 것을 전달하려고합니다. 개선 될 수 있다고 생각되면 자유롭게 편집하십시오.
Mike Chamberlain

어쩌면 "경쟁 상태로 고통받지 않는"것이 더 나은 방법입니다.
Mike Chamberlain 17

10

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)) : "");
}

GetRandomFileName () 메서드는 GUID ()와 비슷할 때마다 항상 고유 한 파일 이름을 생성합니까?
Ashish Shukla

1
@AshishShukla 실제로 나는 전혀 모른다. msdn 은 "암호 적으로 강력한 임의 문자열"이 생성된다고 말합니다. 지금까지 아무런 문제가 없었습니다. 고유성이 중요한 경우 추가 검사를하는 것이 좋습니다.
코레이

3
  1. 일반적인 프로세스에 따라 타임 스탬프가 지정된 파일 이름을 만듭니다.
  2. 파일 이름이 있는지 확인하십시오
  3. 거짓-파일 저장
  4. True-카운터에 추가 문자를 파일에 추가
  5. 2 단계로 이동

10
이 알고리즘은 동시성에 취약하다
Jader Dias

3

사용자 정의 방법없이 고유 한 파일 이름이 자동으로 생성되도록 할 수 있습니다. 다만 다음과 같은 사용 StorageFolder 클래스 또는 StorageFile 클래스 . 여기서 핵심은 다음 CreationCollisionOption.GenerateUniqueNameNameCollisionOption.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);

2

다음 코드를 사용하고 정상적으로 작동합니다. 이것이 도움이되기를 바랍니다.

타임 스탬프를 사용하여 고유 한 파일 이름으로 시작합니다.

"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;
        }
    }

1

파일 이름에 날짜 시간 소인이 필요합니까?

파일 이름을 GUID로 만들 수 있습니다.


@downvoter 다운 투표에 대한 이유가 있습니까? 파일 이름에 대한 GUID는이 질문에 대한 대중적인 답변 인 것 같습니다.
Larry Hipp

반복되는 답변이며
공감

@ XMLforDummies 내 대답은 첫 번째 중 하나였습니다. 지금은 시간을 표시하기 때문에 지금처럼 보이지 않을 수 있습니다. 아마도 정답 일 수 있기 때문에 반복되는 답변입니다.
Larry Hipp


1

Guid.NewGuid()GUID를 만들고 파일 이름으로 사용하거나 파일 이름의 일부로 타임 스탬프와 함께 사용하는 방법은 어떻습니까 ?


1

파일 확장명 앞에 시퀀스 번호를 추가하여 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);
}

스레드 안전 또는 프로세스 안전이 아닙니다. File.Exists 검사와 파일의 생성 (나중에 예상되는)과의 경쟁 조건이 있습니다. 파일을 만들지 않고 행에서 두 번 호출하면 동일한 결과가 반환됩니다.
user2864740

1

아래와 같이 고유 ID를 만들 수없는 이유는 무엇입니까?

DateTime.Now.Ticks와 Guid.NewGuid (). ToString ()을 사용하여 서로 결합하고 고유 한 ID를 만들 수 있습니다.

DateTime.Now.Ticks가 추가되면 고유 ID가 생성 된 날짜 및 시간 (초)을 확인할 수 있습니다.

코드를 참조하십시오.

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.

고유 ID로 진드기의 일부를 취하고 나중에 참조 할 수 있도록 날짜와 시간을 확인할 수도 있습니다.

파일 이름에 생성 된 고유 ID를 첨부하거나 응용 프로그램 또는 웹 사이트에 사용자의 로그인 로그 아웃을위한 고유 세션 ID를 생성하는 데 사용할 수 있습니다.


GUID가 있다면 왜 '틱'을 신경 쓰지 않습니까?
user2864740

시나리오 중에 uniqueSessionId가 언제 생성되는지 확인해야하는 경우 정확한 시간을 얻게됩니다. 또한 그 특정 진드기에 평생 한 번만 발생합니다.
Jineesh Uvantavida

명백히, 진드기에 대한 가정은 유효하지 않습니다. 1) 여러 관찰자가 동일한 '틱'(스레드 / 프로세스 생각)을 볼 수 있으며 2) 충분히 빨리 쿼리하면 동일한 관찰자에 의해 동일한 '틱'이 여러 번 관찰 될 수 있습니다.
user2864740

그러나 으로 사용 Guid.NewGuid (그리고 어떤 경우에는 관심이있을 수있는 "암호 무작위로"아닙니다 그 사실을 무시), 우리는 우리가 약 달리 고유 ID가됩니다 걱정하지 않는 것이 충분히 높은 확률로, 그 주장 할 수 생성-이것은 '틱'보다 훨씬 더 높은 보증 입니다. 따라서, '틱'은 가치가 없으며 여기서 파일 이름에 "보조"데이터를 넣을 것으로 예상됩니다.
user2864740

(FWIW : 방금 언급 한 '고유 시간'에 대한 단정 된 주장으로 일부 코드를 수정했습니다.)
user2864740

0

날짜 시간, 시간, 분 등을 원하면 정적 변수를 사용할 수 있습니다. 이 변수의 값을 파일 이름에 추가하십시오. 카운터를 0으로 시작하고 파일을 만들 때 증분 할 수 있습니다. 이렇게하면 파일에도 초가 있기 때문에 파일 이름이 고유해야합니다.


0

나는 보통이 라인을 따라 무언가를한다 :

  • 스템 파일 이름으로 시작 ( 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 ;
    }

}

알고리즘을 조정하고 싶을 수도 있습니다 (예를 들어 항상 가능한 모든 구성 요소를 파일 이름으로 사용하십시오). 컨텍스트에 따라 달라집니다. 예를 들어 로그 파일을 만드는 중이라면 존재하지 않기를 원한다면 모두 같은 패턴을 이름과 공유하기를 원할 것입니다.

코드가 완벽하지 않습니다 (예 : 전달 된 데이터를 확인하지 않음). 그리고 알고리즘이 완벽하지 않습니다 (하드 드라이브를 채우거나 권한, 실제 I / O 오류 또는 기타 파일 시스템 오류가 발생하면 무한 루프에서 정지됩니다).


0

Day Month Year Second Millisecond 문자열로 GUID를 연결 하고이 솔루션이 내 시나리오에서 상당히 좋다고 생각합니다.



0

나는 이것을하기 위해 특별히 수업을 썼다. "기본"부분 (기본값은 1 분 단위의 정확한 타임 스탬프)으로 초기화 된 후 고유 한 이름을 만들기 위해 문자를 추가합니다. 따라서 생성 된 첫 번째 스탬프가 1907101215a이면 두 번째 스탬프는 1907101215b, 1907101215c 등이됩니다.

25 개 이상의 고유 스탬프가 필요한 경우 단항 'z'를 사용하여 25를 계산합니다. 따라서 1907101215y, 1907101215za, 1907101215zb, ... 1907101215zy, 1907101215zza, 1907101215zzb 등으로 이동합니다. 그러면 스탬프 뒤의 다음 문자가 문자가 아닌 한 스탬프가 항상 알파벳 순서대로 알파벳 순서대로 정렬됩니다.

스레드 안전하지 않고 시간을 자동으로 업데이트하지 않으며 수백 개의 스탬프가 필요한 경우 빠르게 팽창하지만 내 요구에 충분하다는 것을 알았습니다.

/// <summary>
/// Class for generating unique stamps (for filenames, etc.)
/// </summary>
/// <remarks>
/// Each time ToString() is called, a unique stamp is generated.
/// Stamps are guaranteed to sort alphanumerically in order of generation.
/// </remarks>
public class StampGenerator
{
  /// <summary>
  /// All the characters which could be the last character in the stamp.
  /// </summary>
  private static readonly char[] _trailingChars =
  {
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
    'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
    'u', 'v', 'w', 'x', 'y'
  };

  /// <summary>
  /// How many valid trailing characters there are.
  /// </summary>
  /// <remarks>Should always equal _trailingChars.Length</remarks>
  public const int TRAILING_RANGE = 25;

  /// <summary>
  /// Maximum length of the stamp. Hard-coded for laziness.
  /// </summary>
  public const int MAX_LENGTH_STAMP = 28;

  /// <summary>
  /// Base portion of the stamp. Will be constant between calls.
  /// </summary>
  /// <remarks>
  /// This is intended to uniquely distinguish between instances.
  /// Default behavior is to generate a minute-accurate timestamp.
  /// </remarks>
  public string StampBase { get; }

  /// <summary>
  /// Number of times this instance has been called.
  /// </summary>
  public int CalledTimes { get; private set; }

  /// <summary>
  /// Maximum number of stamps that can be generated with a given base.
  /// </summary>
  public int MaxCalls { get; }

  /// <summary>
  /// Number of stamps remaining for this instance.
  /// </summary>
  public int RemainingCalls { get { return MaxCalls - CalledTimes; } }

  /// <summary>
  /// Instantiate a StampGenerator with a specific base.
  /// </summary>
  /// <param name="stampBase">Base of stamp.</param>
  /// <param name="calledTimes">
  /// Number of times this base has already been used.
  /// </param>
  public StampGenerator(string stampBase, int calledTimes = 0)
  {
    if (stampBase == null)
    {
      throw new ArgumentNullException("stampBase");
    }
    else if (Regex.IsMatch(stampBase, "[^a-zA-Z_0-9 \\-]"))
    {
      throw new ArgumentException("Invalid characters in Stamp Base.",
                                  "stampBase");
    }
    else if (stampBase.Length >= MAX_LENGTH_STAMP - 1)
    {
      throw new ArgumentException(
        string.Format("Stamp Base too long. (Length {0} out of {1})",
                      stampBase.Length, MAX_LENGTH_STAMP - 1), "stampBase");
    }
    else if (calledTimes < 0)
    {
      throw new ArgumentOutOfRangeException(
        "calledTimes", calledTimes, "calledTimes cannot be negative.");
    }
    else
    {
      int maxCalls = TRAILING_RANGE * (MAX_LENGTH_STAMP - stampBase.Length);
      if (calledTimes >= maxCalls)
      {
        throw new ArgumentOutOfRangeException(
          "calledTimes", calledTimes, string.Format(
            "Called Times too large; max for stem of length {0} is {1}.",
            stampBase.Length, maxCalls));
      }
      else
      {
        StampBase = stampBase;
        CalledTimes = calledTimes;
        MaxCalls = maxCalls;
      }
    }
  }

  /// <summary>
  /// Instantiate a StampGenerator with default base string based on time.
  /// </summary>
  public StampGenerator() : this(DateTime.Now.ToString("yMMddHHmm")) { }

  /// <summary>
  /// Generate a unique stamp.
  /// </summary>
  /// <remarks>
  /// Stamp values are orered like this:
  /// a, b, ... x, y, za, zb, ... zx, zy, zza, zzb, ...
  /// </remarks>
  /// <returns>A unique stamp.</returns>
  public override string ToString()
  {
    int zCount = CalledTimes / TRAILING_RANGE;
    int trailing = CalledTimes % TRAILING_RANGE;
    int length = StampBase.Length + zCount + 1;

    if (length > MAX_LENGTH_STAMP)
    {
      throw new InvalidOperationException(
        "Stamp length overflown! Cannot generate new stamps.");
    }
    else
    {
      CalledTimes = CalledTimes + 1;
      var builder = new StringBuilder(StampBase, length);
      builder.Append('z', zCount);
      builder.Append(_trailingChars[trailing]);
      return builder.ToString();
    }
  }
}

-1

DateTime.Now.Ticks안전하지 않습니다, Guid.NewGuid()당신은 깨끗하고 뭔가해야하는 경우, 너무 못생긴 거의 (안전을 당신이 1ms에서 100 번을 호출하는 경우는 예를 들어 100 % 안전하지 ), 시도 :

Math.Abs(Guid.NewGuid().GetHashCode())

안전하다는 것은 매우 짧은 시간에 몇 ms 동안 그렇게 여러 번 부를 때 독특하게 안전하다는 것을 의미합니다 .


솔루션 다운 보터에 문제가 있습니까? 알려주세요.
Mehdi Dehghani

GetHashCode메서드 int는 32 비트 범위를 갖는을 반환 하지만 a GUID는 128 비트 범위를 가지므로 훨씬 더 고유 할 가능성이 높습니다. GUID값 의 형식이 마음에 들지 않으면 간단히 호출 ToString("N")하여 대시를 제거하십시오.
4thex
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.