Jak generować unikalne nazwy plików w C #


133

Zaimplementowałem algorytm, który będzie generował unikalne nazwy dla plików, które będą zapisywać na dysku twardym. Dołączam DateTime: godziny, minuty, sekundy i milisekundy, ale nadal generuje zduplikowane nazwy plików, ponieważ przesyłam wiele plików naraz.

Jakie jest najlepsze rozwiązanie do generowania unikalnych nazw plików, które mają być przechowywane na dysku twardym, aby żadne 2 pliki nie były takie same?


To zależy od innych wymagań; to [stare] pytanie było / jest zbyt niejasne.
user2864740

Odpowiedzi:


244

Jeśli czytelność nie ma znaczenia, użyj identyfikatorów GUID .

Na przykład:

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

lub krócej :

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

W moich programach czasami próbuję np. 10 razy wygenerować czytelną nazwę („Image1.png”… „Image10.png”) i jeśli to się nie powiedzie (ponieważ plik już istnieje), wracam do GUID.

Aktualizacja:

Ostatnio DateTime.Now.Tickszamiast identyfikatorów GUID używam :

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

lub

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

Korzyścią dla mnie jest to, że generuje to krótszą i ładniej wyglądającą nazwę pliku w porównaniu z identyfikatorami GUID.

Należy pamiętać, że w niektórych przypadkach (np. Podczas generowania wielu losowych nazw w bardzo krótkim czasie) może to spowodować powstanie nieunikalnych wartości.

Trzymaj się identyfikatorów GUID, jeśli chcesz naprawdę upewnić się, że nazwy plików są unikalne, nawet podczas przesyłania ich na inne komputery.


7
Lubię używać Ticks jako GUID jest naprawdę brzydki. Możesz również uzyskać skrót znaczników, który zmniejsza długość znaków w nazwie pliku. DateTime.Now.Ticks.GetHashCode().ToString("x").ToUpper()
WillMcKill

4
„Ticks” jest przewidywalny i nie jest bezpieczny dla wątków (ponieważ te same „tiki” można uzyskać z wielu wątków / procesów). To sprawia, że ​​nie nadaje się do generowania tymczasowych nazw plików. Generowanie X..1..N może być odpowiednie do zadań skierowanych do użytkownika (np. Kopiowanie w Eksploratorze), ale jest wątpliwe dla pracy serwera.
user2864740

92

Posługiwać się

Path.GetTempFileName()

lub użyj nowego identyfikatora GUID ().

Path.GetTempFilename () w witrynie MSDN .


Oto link do dokumentu MSDN: msdn.microsoft.com/en-us/library/ ...
epotter

3
Pamiętaj jednak, że GetTempFileName()może to spowodować wyjątek, jeśli utworzysz wiele takich plików bez ich usuwania.
Joey

21
„Metoda GetTempFileName zgłosi wyjątek IOException, jeśli zostanie użyta do utworzenia ponad 65535 plików bez usuwania poprzednich plików tymczasowych”. mówi artykuł MSDN.
Çağdaş Tekin

1
UWAGA: GetTempFileNamebędzie utworzyć plik. Oznacza to również, że wybiera tymczasową lokalizację ścieżki . Z drugiej strony GetRandomFileNamejest odpowiednie do wygenerowania nazwy pliku 8.3, której można użyć z inną ścieżką. (Widziałem jakiś okropny kod, który używa GetTempFileName z File.Delete tylko po to, aby użyć nazwy pliku w innym miejscu ..)
user2864740


54

Jeśli czytelność nazwy pliku nie jest ważna, wystarczy GUID, jak sugeruje wielu. Jednak uważam, że przeglądanie katalogu zawierającego 1000 nazw plików GUID jest bardzo trudne. Dlatego zwykle używam kombinacji statycznego ciągu znaków, który nadaje nazwie pliku pewne informacje o kontekście, sygnaturę czasową i identyfikator GUID.

Na przykład:

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

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

W ten sposób, gdy sortuję według nazwy pliku, automatycznie grupuje pliki według ciągu kontekstowego i sortuje według sygnatury czasowej.

Zwróć uwagę, że limit nazw plików w systemie Windows wynosi 255 znaków.


1
+1 Aby sugestia zawierała przydatne informacje w połączeniu z identyfikatorem GUID. - Na bok z przymrużeniem oka: umieszczanie daty i godziny w nazwie pliku jest trochę zbędne, jeśli możesz Right Click > Sort By > Date.
Timothy Shields

1
Czas staje się przydatny, jeśli przechowujesz kilka plików w różnych kontekstach w tym samym katalogu. Oczywiście generowanie nazwy pliku powinno być dostosowane do twoich konkretnych potrzeb.
Mas

Powinien być Guid.NewGuid().ToString();. Brak nawiasu. +1 inaczej
Laurent W.

To jest bardzo sprytne. Timestamp i Guid. +1
JoshYates1980

Podoba mi się to rozwiązanie +1, dodałem drugie rozszerzenie ciągu parametrów, które dodaję do fileName, to dodatkowo wspiera ideę kontekstu i pozwala łatwo otworzyć plik domyślną aplikacją po dwukrotnym kliknięciu, jeśli to konieczne
shelbypereira

23

Oto algorytm, który zwraca unikalną, czytelną nazwę pliku na podstawie dostarczonego oryginału. Jeśli oryginalny plik istnieje, próbuje przyrostowo dołączyć indeks do nazwy pliku, aż znajdzie taki, który nie istnieje. Wczytuje istniejące nazwy plików do HashSet, aby sprawdzić kolizje, więc jest dość szybki (kilkaset nazw plików na sekundę na moim komputerze), jest również bezpieczny dla wątków i nie cierpi na warunki wyścigu.

Na przykład, jeśli go zdasz test.txt, spróbuje utworzyć pliki w następującej kolejności:

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

itd. Możesz określić maksymalną liczbę prób lub po prostu pozostawić ją domyślną.

Oto pełny przykład:

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

bezpieczne wątkowo ? niestatic readonly zmienna teżlock?
Kiquenet,

Sama metoda jest statyczna, więc nic nie udostępnia, więc uważam, że wiele wątków może bezpiecznie wejść do tej metody jednocześnie. Być może wątek bezpieczny nie jest całkiem poprawnym terminem - staram się przekazać, że jeśli inny wątek / proces utworzy plik o sprzecznej nazwie podczas wykonywania, ta metoda odzyskuje i próbuje kolejną dostępną nazwę. Nie krępuj się edytować, jeśli uważasz, że można to poprawić.
Mike Chamberlain

Być może „nie cierpiący na stan rasy” to lepszy sposób na określenie tego.
Mike Chamberlain

11

Używam GetRandomFileName :

Metoda GetRandomFileName zwraca silny kryptograficznie, losowy ciąg, którego można użyć jako nazwy folderu lub nazwy pliku. W przeciwieństwie do GetTempFileName, GetRandomFileName nie tworzy pliku. Gdy bezpieczeństwo systemu plików jest najważniejsze, ta metoda powinna być używana zamiast GetTempFileName.

Przykład:

public static string GenerateFileName(string extension="")
{
    return string.Concat(Path.GetRandomFileName().Replace(".", ""),
        (!string.IsNullOrEmpty(extension)) ? (extension.StartsWith(".") ? extension : string.Concat(".", extension)) : "");
}

Czy metoda GetRandomFileName () zawsze generuje unikalną nazwę pliku za każdym razem podobnie do GUID ()?
Ashish Shukla

1
@AshishShukla właściwie nie mam pojęcia. msdn mówi, że generowany jest „silny kryptograficznie, losowy ciąg”. Jak dotąd nie miałem żadnych problemów. Jeśli wyjątkowość jest krytyczna, dodatkowe sprawdzenie może być dobrym pomysłem.
Koray

Należy zauważyć, że firma Microsoft z jakiegoś powodu usunęła cytowany tekst. Teraz dokumenty po prostu mówią „Zwraca losową nazwę folderu lub nazwę pliku”.
Bip901

3
  1. Utwórz nazwę pliku ze znacznikiem czasu zgodnie z normalnym procesem
  2. Sprawdź, czy nazwa pliku istnieje
  3. Fałsz - zapisz plik
  4. Prawda - dołącz dodatkowy znak do pliku, na przykład licznik
  5. Przejdź do kroku 2

10
Ten algorytm jest podatny na współbieżność
Jader Dias,

3

Możesz mieć automatycznie wygenerowaną unikalną nazwę pliku bez żadnych niestandardowych metod. Po prostu użyj następujących z klasą StorageFolder lub StorageFile . Kluczem tutaj jest: CreationCollisionOption.GenerateUniqueNameiNameCollisionOption.GenerateUniqueName

Aby utworzyć nowy plik z unikalną nazwą:

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

Aby skopiować plik do lokalizacji o unikalnej nazwie:

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

Aby przenieść plik o unikalnej nazwie w lokalizacji docelowej:

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

Aby zmienić nazwę pliku z unikalną nazwą w lokalizacji docelowej:

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

2

Czy potrzebujesz znacznika daty i czasu w nazwie pliku?

Możesz uczynić nazwę pliku identyfikatorem GUID.


@downvoter Czy jest jakiś powód do głosowania negatywnego? Popularną odpowiedzią na to pytanie wydaje się być identyfikator GUID dla nazwy pliku.
Larry Hipp,

Jest to powtarzane odpowiedź, i nie mam wystarczającej reputacji downvote
Jader Dias

@XMLforDummies moja odpowiedź była jedną z pierwszych. Może się tak nie wydawać, ponieważ teraz pokazuje tylko godziny. To powtórzona odpowiedź, ponieważ prawdopodobnie jest to poprawna odpowiedź.
Larry Hipp,


2

Używałem następującego kodu i działa poprawnie. Mam nadzieję, że to ci pomoże.

Rozpoczynam od unikalnej nazwy pliku przy użyciu sygnatury czasowej -

„context_” + DateTime.Now.ToString („rrrrMMddHHmmssffff”)

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

2

Dlaczego nie możemy stworzyć unikalnego identyfikatora, jak poniżej.

Możemy użyć DateTime.Now.Ticks i Guid.NewGuid (). ToString (), aby połączyć razem i stworzyć unikalny identyfikator.

Po dodaniu DateTime.Now.Ticks możemy znaleźć datę i godzinę w sekundach, w których tworzony jest unikalny identyfikator.

Proszę zobaczyć kod.

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.

Możemy nawet wziąć część ticków w unikalnym identyfikatorze i sprawdzić później datę i godzinę do wykorzystania w przyszłości.

Możesz dołączyć unikalny identyfikator utworzony do nazwy pliku lub możesz go użyć do stworzenia unikalnego identyfikatora sesji do logowania i wylogowywania użytkowników z naszej aplikacji lub strony internetowej.


Po co zawracać sobie głowę „kleszczami”, jeśli istnieje identyfikator GUID?
user2864740

W każdym scenariuszu, jeśli chcesz sprawdzić, kiedy generowany jest identyfikator uniqueSessionId, otrzymasz dokładny czas. A także w tym konkretnym tiku nastąpi tylko raz w życiu.
Jineesh Uvantavida

W rzeczywistości założenie dotyczące tików jest nieważne: 1) wielu obserwatorów może zobaczyć ten sam „tik” (wątki myślowe / procesy) i 2) ten sam „tik” może być zaobserwowany wiele razy przez tego samego obserwatora, jeśli zostanie zapytany wystarczająco szybko.
user2864740

Jednak po prostu używając Guid.NewGuid (i ignorując fakt, że nie jest to „kryptograficznie losowy”, co może być interesujące w niektórych przypadkach), możemy stwierdzić, że z wystarczająco dużym prawdopodobieństwem, że nie obchodzi nas inaczej, unikalny identyfikator będzie być generowane - jest to znacznie, dużo wyższa gwarancja niż „kleszcze” . W związku z tym „zaznaczenia” nie mają żadnej wartości / należy ich tutaj używać jako danych „drugorzędnych” umieszczonych w nazwie pliku.
user2864740

(FWIW: Właśnie naprawiłem kod ze zepsutym wcześniej wspomnianym stwierdzeniem o „unikalnym czasie” ..)
user2864740

1

Co powiesz Guid.NewGuid()na utworzenie identyfikatora GUID i użycie go jako nazwy pliku (lub części nazwy pliku wraz ze znacznikiem czasu, jeśli chcesz).


1

Napisałem prostą funkcję rekurencyjną, która generuje nazwy plików, tak jak robi to Windows, dodając numer sekwencyjny przed rozszerzeniem pliku.

Biorąc pod uwagę żądaną ścieżkę do pliku C:\MyDir\MyFile.txt, a plik już istnieje, zwraca ostateczną ścieżkę do pliku C:\MyDir\MyFile_1.txt.

Nazywa się to tak:

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

To nie jest bezpieczne dla wątków ani dla procesów. Występuje warunek wyścigu z kontrolą File.Exists i (później przypuszczalnym) utworzeniem pliku. Co oczywiste, wywołanie dwa razy z rzędu bez tworzenia pliku zwróci ten sam wynik.
user2864740

0

Jeśli chcesz mieć datę i godzinę, godziny, minuty itp., Możesz użyć zmiennej statycznej. Dołącz wartość tej zmiennej do nazwy pliku. Możesz rozpocząć licznik od 0 i zwiększać po utworzeniu pliku. W ten sposób nazwa pliku z pewnością będzie unikalna, ponieważ masz również sekundy w pliku.


0

Zwykle robię coś w ten sposób:

  • zacznij od nazwy pliku macierzystego ( work.dat1na przykład)
  • spróbuj utworzyć go za pomocą CreateNew
  • jeśli to zadziała, masz plik, w przeciwnym razie ...
  • zmieszaj aktualną datę / godzinę z nazwą pliku ( work.2011-01-15T112357.datna przykład)
  • spróbuj utworzyć plik
  • jeśli to zadziałało, masz plik, w przeciwnym razie ...
  • Dodaj monotoniczny licznik do nazwy pliku ( work.2011-01-15T112357.0001.datna przykład (nie lubię identyfikatorów GUID, wolę porządek / przewidywalność).
  • spróbuj utworzyć plik. Kontynuuj zaznaczanie licznika i ponawiaj próby, aż zostanie utworzony plik.

Oto przykładowa klasa:

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

}

Możesz zmienić algorytm (na przykład zawsze używaj wszystkich możliwych składników nazwy pliku). Zależy od kontekstu - gdybym tworzył na przykład pliki dziennika, które chciałbym usunąć z istnienia, chciałbyś, aby wszystkie miały ten sam wzorzec z nazwą.

Kod nie jest doskonały (na przykład brak kontroli przekazanych danych). A algorytm nie jest doskonały (jeśli zapełnisz dysk twardy lub napotkasz uprawnienia, rzeczywiste błędy we / wy lub inne błędy systemu plików, na przykład zawiesi się w nieskończonej pętli).


0

Kończy się łączeniem GUID z ciągiem dzień miesiąc rok druga milisekunda i myślę, że to rozwiązanie jest całkiem dobre w moim scenariuszu



0

Napisałem zajęcia specjalnie w tym celu. Jest inicjowany częścią „podstawową” (domyślnie jest to znacznik czasu z dokładnością co do minuty), a następnie dołącza litery, aby utworzyć unikalne nazwy. Tak więc, jeśli pierwszy wygenerowany znaczek to 1907101215a, drugi to 1907101215b, następnie 1907101215c i tak dalej.

Jeśli potrzebuję więcej niż 25 unikalnych znaczków, używam jednoargumentowych „z”, aby policzyć 25. Więc to idzie 1907101215y, 1907101215za, 1907101215zb, ... 1907101215zy, 1907101215zza, 1907101215zzb i tak dalej. Gwarantuje to, że znaczki zawsze będą sortowane alfanumerycznie w kolejności, w jakiej zostały wygenerowane (o ile następny znak po znaczku nie jest literą).

Nie jest bezpieczny dla wątków, nie aktualizuje automatycznie czasu i szybko się rozrasta, jeśli potrzebujesz setek znaczków, ale uważam, że jest wystarczający dla moich potrzeb.

/// <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();
    }
  }
}

0

DateTime.Now.Ticksnie jest bezpieczny, Guid.NewGuid()jest zbyt brzydki, jeśli potrzebujesz czegoś czystego i prawie bezpiecznego ( nie jest w 100% bezpieczne, na przykład, jeśli wywołasz to 1000000 razy w 1 ms ), spróbuj:

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

Przez bezpieczny mam na myśli bycie wyjątkowym, kiedy nazywasz to tak wiele razy w bardzo krótkim okresie kilku ms .


Czy jest jakiś problem z odbiorcą mojego rozwiązania? proszę daj mi znać.
Mehdi Dehghani

GetHashCodeMetody zwracającej int, który ma zakres 32-bitowego, podczas gdy GUIDposiada szereg 128 bitów, a więc jest bardziej prawdopodobne jest unikatowy. Jeśli nie podoba ci się format GUIDwartości, po prostu wywołaj ToString("N")go, co spowoduje usunięcie myślników.
4thex

Tak, ale jak już wspomniałem Guid.NewGuid()jest brzydki i długo vs GetHashCode()np: 83c5bf1722f64937a01bcf46531ee385vs 899709107. oczywiście w zależności od sytuacji rozwiązanie będzie inne, to jest moje rozwiązanie, które bez problemu wykorzystywałem przez ostatnie 6 lat we wszystkich swoich projektach.
Mehdi Dehghani
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.