Como gerar nomes de arquivo exclusivos em c #


131

Eu implementei um algoritmo que irá gerar nomes exclusivos para arquivos que serão salvos no disco rígido. Estou acrescentando DateTime: Horas, Minutos, Segundos e Milissegundos, mas ainda gera nomes duplicados de arquivos porque estou carregando vários arquivos de uma vez.

Qual é a melhor solução para gerar nomes exclusivos para os arquivos a serem armazenados no disco rígido, para que não haja dois arquivos iguais?


Depende de outros requisitos; essa [velha] pergunta era / é muito vaga.
User2864740 de

Respostas:


240

Se a legibilidade não interessar, use GUIDs .

Por exemplo:

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

ou mais curto :

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

Nos meus programas, às vezes tento, por exemplo, 10 vezes gerar um nome legível ("Image1.png" ... "Image10.png") e, se isso falhar (porque o arquivo já existe), volto aos GUIDs.

Atualizar:

Recentemente, também usei em DateTime.Now.Ticksvez de GUIDs:

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

ou

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

O benefício para mim é que isso gera um nome de arquivo mais curto e de "aparência mais agradável", comparado aos GUIDs.

Observe que em alguns casos (por exemplo, ao gerar muitos nomes aleatórios em um tempo muito curto), isso pode gerar valores não exclusivos.

Atenha-se aos GUIDs se quiser ter certeza de que os nomes dos arquivos sejam exclusivos, mesmo quando os transferir para outros computadores.


7
Eu gosto de usar carrapatos como um GUID é realmente feio. Você também pode obter um hash dos Ticks, o que reduz o tamanho dos caracteres do nome do arquivo. DateTime.Now.Ticks.GetHashCode().ToString("x").ToUpper()
WillMcKill

4
Os "tiques" são previsíveis e não são seguros para threads (como os mesmos 'ticks' podem ser obtidos em vários threads / processos). Isso o torna inadequado para a geração de nome de arquivo temporário. A geração de X..1..N pode ser adequada para tarefas voltadas para o usuário (por exemplo, copiar no Explorer), mas é duvidosa para o trabalho do servidor.
User2864740

90

Usar

Path.GetTempFileName()

ou use o novo GUID ().

Path.GetTempFilename () no MSDN .


Aqui está o link para o documento do MSDN: msdn.microsoft.com/en-us/library/…
epotter

3
Observe, porém, que isso GetTempFileName()pode gerar uma exceção se você criar muitos desses arquivos sem excluí-los.
Joey

21
"O método GetTempFileName gerará uma IOException se for usado para criar mais de 65535 arquivos sem excluir arquivos temporários anteriores." diz o artigo do MSDN.
Çağdaş Tekin

1
AVISO: GetTempFileNamevai criar um arquivo. Isso também significa que ele escolhe o local do caminho temporário . Por outro lado, GetRandomFileNameé adequado para gerar um nome de arquivo 8.3 que pode ser usado com um caminho diferente. (Eu vi algum código horrível que usa GetTempFileName com um File.Delete apenas para usar o nome do arquivo em outro lugar ..)
user2864740


54

Se a legibilidade do nome do arquivo não for importante, o GUID, como sugerido por muitos, será útil. No entanto, acho que procurar em um diretório com 1000 nomes de arquivos GUID é muito assustador de se classificar. Então, eu costumo usar uma combinação de uma sequência estática que fornece ao nome do arquivo algumas informações de contexto, um carimbo de data e hora e GUID.

Por exemplo:

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

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

Dessa forma, quando eu classifico por nome de arquivo, ele agrupa automaticamente os arquivos pela string de contexto e classifica por timestamp.

Observe que o limite do nome do arquivo no Windows é de 255 caracteres.


1
+1 Para que a sugestão inclua informações úteis combinadas com um GUID. - Um aspecto a ser levado com um pouco de sal: incluir a data e a hora em um nome de arquivo é meio redundante quando você pode simplesmente Right Click > Sort By > Date.
amigos estão dizendo sobre timothy

1
O tempo se torna útil se você estiver armazenando vários arquivos com contextos diferentes no mesmo diretório. Obviamente, a geração do nome do arquivo deve ser ajustada com base em suas necessidades específicas.
Mas

Deveria ser Guid.NewGuid().ToString();. Parênteses ausentes. +1 caso contrário
Laurent W.

Isso é muito liso. Registro de data e hora e Guid. 1
JoshYates1980

Eu gosto desta solução +1, eu adicionei uma extensão corda segundo parâmetro que eu adicionar ao nome do arquivo, este ainda apoia a ideia de contexto e permite facilmente abrir o arquivo com o aplicativo padrão de duplo clique, se necessário
shelbypereira

23

Aqui está um algoritmo que retorna um nome de arquivo legível exclusivo com base no original fornecido. Se o arquivo original existir, ele incrementalmente tenta anexar um índice ao nome do arquivo até encontrar um que não exista. Ele lê os nomes de arquivos existentes em um HashSet para verificar colisões, para que seja bem rápido (algumas centenas de nomes de arquivos por segundo na minha máquina), é seguro para threads também e não sofre condições de corrida.

Por exemplo, se você o passar test.txt, ele tentará criar arquivos nesta ordem:

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

etc. Você pode especificar o máximo de tentativas ou simplesmente deixá-lo no padrão.

Aqui está um exemplo completo:

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

thread-safe ? não éstatic readonly variável tambémlock?
21417

O método em si é estático, portanto, não compartilha nada; portanto, acredito que vários threads possam entrar com segurança nesse método simultaneamente. Talvez thread-safe não seja o termo correto - estou tentando transmitir que, se outro thread / processo criar um arquivo com um nome conflitante durante a execução, esse método será recuperado e tentará o próximo nome disponível. Sinta-se livre para editar se você acha que pode ser melhorado.
Mike Chamberlain

Talvez "não sofra de uma condição de raça" seja a melhor maneira de colocá-lo.
Mike Chamberlain

10

Eu uso GetRandomFileName :

O método GetRandomFileName retorna uma sequência aleatória criptograficamente forte que pode ser usada como um nome de pasta ou um nome de arquivo. Ao contrário de GetTempFileName, GetRandomFileName não cria um arquivo. Quando a segurança do seu sistema de arquivos é primordial, esse método deve ser usado em vez de GetTempFileName.

Exemplo:

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

O método GetRandomFileName () sempre gera o nome do arquivo exclusivo sempre que semelhante ao GUID ()?
Ashish Shukla

1
@AshishShukla na verdade eu não tenho ideia. O msdn diz que "uma sequência aleatória criptograficamente forte" é gerada. Até agora não tive problemas. Se a exclusividade for crítica, uma verificação extra pode ser uma boa ideia.
precisa

3
  1. Crie seu nome de arquivo com carimbo de data e hora seguindo seu processo normal
  2. Verifique se o nome do arquivo existe
  3. Falso - salvar arquivo
  4. Verdadeiro - acrescenta caracteres adicionais ao arquivo, talvez um contador
  5. Avance para o passo 2

10
Esse algoritmo é passível de concorrência
Jader Dias

3

Você pode ter um nome de arquivo exclusivo gerado automaticamente para você, sem nenhum método personalizado. Basta usar o seguinte com a classe StorageFolder ou a classe StorageFile . A chave aqui é: CreationCollisionOption.GenerateUniqueNameeNameCollisionOption.GenerateUniqueName

Para criar um novo arquivo com um nome de arquivo exclusivo:

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

Para copiar um arquivo para um local com um nome de arquivo exclusivo:

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

Para mover um arquivo com um nome de arquivo exclusivo no local de destino:

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

Para renomear um arquivo com um nome de arquivo exclusivo no local de destino:

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

2

Eu tenho usado o código a seguir e está funcionando bem. Espero que isso possa ajudá-lo.

Começo com um nome de arquivo exclusivo usando um carimbo de data e hora -

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

Código 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

Você precisa da data e hora no nome do arquivo?

Você pode tornar o nome do arquivo um GUID.


@ downvoter Alguma razão para o voto negativo? Um GUID para um nome de arquivo parece ser uma resposta popular a esta pergunta.
Larry Hipp 11/01

É uma resposta repetiu, e eu não tenho reputação suficiente para downvote
Jader Dias

@XMLforDummies minha resposta foi uma das primeiras. Pode não parecer agora, porque apenas mostra as horas até agora. É uma resposta repetida, porque provavelmente é a resposta correta.
Larry Hipp 11/01


1

Que tal usar Guid.NewGuid()para criar um GUID e usá-lo como o nome do arquivo (ou parte do nome do arquivo junto com o carimbo de data / hora, se desejar).


1

Eu escrevi uma função recursiva simples que gera nomes de arquivos como o Windows, acrescentando um número de sequência antes da extensão do arquivo.

Dado um caminho de arquivo desejado de C:\MyDir\MyFile.txt, e o arquivo já existe, ele retorna um caminho de arquivo final de C:\MyDir\MyFile_1.txt.

É chamado assim:

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

Isso não é seguro para thread ou para processo. Há uma condição de corrida com a verificação File.Exists e qualquer criação (suposta posteriormente) do arquivo. Trivialmente, quando chamado duas vezes seguidas sem criar um arquivo, ele retornará o mesmo resultado.
User2864740

1

Por que não podemos criar um ID exclusivo, como abaixo.

Podemos usar DateTime.Now.Ticks e Guid.NewGuid (). ToString () para combinar e criar um ID exclusivo.

À medida que o DateTime.Now.Ticks é adicionado, podemos descobrir a Data e a Hora em segundos nos quais o ID exclusivo é criado.

Por favor, veja o código.

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.

Podemos até fazer parte dos ticks em ID único e verificar a data e a hora mais tarde para referência futura.

Você pode anexar o ID exclusivo criado ao nome do arquivo ou pode ser usado para criar um ID de sessão exclusivo para logout de usuários no nosso aplicativo ou site.


Por que se preocupar com 'ticks' se houver um GUID?
User2864740 de

Durante qualquer cenário, se você precisar verificar quando o uniqueSessionId é gerado, receberá a hora exata. E também nesse carrapato específico ocorrerá apenas uma vez na vida.
Jineesh Uvantavida

Trivialmente, essa suposição sobre ticks é inválida: 1) vários observadores podem ver o mesmo 'tick' (processos / threads) e 2) o mesmo 'tick' pode ser observado várias vezes pelo mesmo observador, se consultado com rapidez suficiente.
User2864740

No entanto, por simplesmente usando Guid.NewGuid (e ignorando esse fato não é "criptograficamente aleatória", que pode ser de interesse em alguns casos), podemos afirmar que, com uma probabilidade suficientemente elevada que não se preocupam com o contrário, uma identificação única vai ser gerado - esta é uma garantia muito, muito mais alta do que 'ticks' . Assim, os 'ticks' não têm valor / uso aqui esperado como dados "secundários" inseridos no nome do arquivo.
User2864740

(FWIW: Eu apenas fixo algum código com uma afirmação acima mencionada quebrado sobre 'momento único' ..)
user2864740

0

Se você deseja ter a data e hora, horas, minutos, etc., você pode usar uma variável estática. Anexe o valor dessa variável ao nome do arquivo. Você pode iniciar o contador com 0 e incrementar quando tiver criado um arquivo. Dessa forma, o nome do arquivo certamente será exclusivo, pois você também possui segundos no arquivo.


0

Eu costumo fazer algo nesse sentido:

  • comece com um nome de arquivo-tronco ( work.dat1por exemplo)
  • tente criá-lo com CreateNew
  • se isso funcionar, você tem o arquivo, caso contrário ...
  • misture a data / hora atual no nome do arquivo ( work.2011-01-15T112357.datpor exemplo)
  • tente criar o arquivo
  • se funcionou, você tem o arquivo, caso contrário ...
  • Misture um contador monotônico no nome do arquivo ( work.2011-01-15T112357.0001.datpor exemplo. (Não gosto de GUIDs. Prefiro ordem / previsibilidade).
  • tente criar o arquivo. Continue marcando o contador e tentando novamente até que um arquivo seja criado para você.

Aqui está um exemplo de classe:

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

}

Você pode ajustar o algoritmo (sempre use todos os componentes possíveis no nome do arquivo, por exemplo). Depende do contexto - se eu estivesse criando arquivos de log, por exemplo, que talvez eu deixasse de existir, você desejaria que todos eles compartilhassem o mesmo padrão com o nome.

O código não é perfeito (nenhuma verificação nos dados passados, por exemplo). E o algoritmo não é perfeito (se você preencher o disco rígido ou encontrar permissões, erros de E / S reais ou outros erros do sistema de arquivos, por exemplo, isso travará, como está, em um loop infinito).


0

Eu acabo concatenando o GUID com a sequência Dia Mês Ano Segundo Milissegundo e acho que essa solução é muito boa no meu cenário



0

Eu escrevi uma aula especificamente para fazer isso. É inicializado com uma parte "base" (o padrão é um carimbo de data / hora com precisão de minutos) e depois acrescenta letras para criar nomes exclusivos. Portanto, se o primeiro carimbo gerado for 1907101215a, o segundo seria 1907101215b, 1907101215c, etc.

Se eu precisar de mais de 25 selos exclusivos, utilizarei z unários para contar 25. Então, ele vai 1907101215y, 1907101215za, 1907101215zb, ... 1907101215zy, 1907101215zza, 1907101215zzb e assim por diante. Isso garante que os carimbos sempre sejam classificados alfanumericamente na ordem em que foram gerados (desde que o próximo caractere após o carimbo não seja uma letra).

Não é seguro para threads, não atualiza automaticamente a hora e incha rapidamente se você precisar de centenas de carimbos, mas acho que é suficiente para minhas necessidades.

/// <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.Ticksnão é seguro, Guid.NewGuid()é muito feio, se você precisar de algo limpo e quase seguro ( não é 100% seguro, por exemplo, se você chamar 1.000.000 de vezes em 1ms ), tente:

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

Por seguro, quero dizer que é seguro ser único quando você o chama tantas vezes em um período muito curto, alguns ms de tempo.


Existe algum problema com o downvoter da minha solução? Por favor deixe-me saber.
Mehdi Dehghani 20/04

O GetHashCodemétodo retorna um int, que possui um intervalo de 32 bits, enquanto que um GUIDtem um intervalo de 128 bits e, portanto, é muito mais provável que seja exclusivo. Se você não gostar do formato de um GUIDvalor, basta chamá ToString("N")-lo, o que remove os traços.
4thex
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.