如何在C#中生成8字节的GUID值?

5

1
你只有8个字节的空间,可选项不多。碰撞的风险很高。 - Pierre-Alain Vigeant
6
“@Pierre-Alain: 没有很多可能性?你写过拥有超过2^64个用户的应用程序吗?;)” - Jon Skeet
@Linney:哇塞,16字节可以得到128位,也就是2^128 = (2^10)^(12.8) ~ (10^3)^(12.8) ~ 10^38种组合。 - jason
@ Ramhound 如果用户已经登录,他们的密钥将存储在内存中,直到用户会话结束,这就是为什么密钥长度会超载内存并且我需要限制其长度的原因,Ramhound,你有任何想法吗? - Linney
@Stripling:这是非常有价值的考虑,我可能需要将服务分离到专用服务器上,如果使用GUID并且请求高达10,000次(160M内存),这将解决问题。感谢你的建议,Stripling。 - Linney
显示剩余7条评论
7个回答

9
以下代码将生成具有密码学唯一性的8个字符字符串:
 using System; 
using System.Security.Cryptography;
using System.Text;

namespace JustForFun
{


    public class UniqueId
    {   
        public static string GetUniqueKey()
        {
            int maxSize = 8;
            char[] chars = new char[62];
            string a;
            a = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            chars = a.ToCharArray();
            int size = maxSize;
            byte[] data = new byte[1];
            RNGCryptoServiceProvider crypto = new RNGCryptoServiceProvider();
            crypto.GetNonZeroBytes(data);
            size = maxSize;
            data = new byte[size];
            crypto.GetNonZeroBytes(data);
            StringBuilder result = new StringBuilder(size);
            foreach (byte b in data)
            { result.Append(chars[b % (chars.Length - 1)]); }
            return result.ToString();
        }   
    }
}

4
如果你想要具有加密独特性的密钥,那么这并不过分保险。这是你的选择。 - Peter Bromberg
2
不要认为你需要 chars.Length - 1。N mod X 的最大值总是 X - 1。 - John Gibb
1
我知道这个问题很老了,但您介意解释一下如何使用它使字符串变得唯一吗?它们有多独特?如果我在不同的时间点在循环中使用此函数,它们是否会继续保持唯一? - JuhaKangas
1
@PeterBromberg,将maxSize更改为6,也会是独一无二的吗? - Mohammad Olfatmiri
你不能说它是唯一的,循环几百万次后就会出现冲突。它有很高的可能性是唯一的,但没有像Guid.NewGuid()那样保证,因为它只有128位。 - RassK
显示剩余2条评论

3

在 .net 中,long integer 的大小为 8 字节。你可以从零开始使用一个密钥,每当用户到来时将其增加一。这将为比地球上的人类更多的用户生成唯一的密钥。

如果这不能解决你的问题,请告诉我们更多关于你的限制。


你可以从零开始,每次增加一。你的意思是通过更改每个字节的位(0->255)来增加字节值吗? - Linney
@Linney,他所描述的是特定数据库表上标识符的标准做法。第一个用户获得ID 1,第二个用户是2,第三个是3,以此类推。然而,这取决于有一个单一的地方生成这些ID,因为如果两个不同的系统将ID 3分配给不同的用户,然后他们尝试共享用户,那么这两个用户将具有相同的ID。 - StriplingWarrior
Stripling - 是的,这是真的,而且这样做并不好,嗯。 - Linney

2

生成一个随机的长整型数,然后将其转换为十六进制字符串。

或者可以直接从 unsigned long 顺序分配。


是的,如果你要做这件事,我想这可能比大多数策略都更简单。 - StriplingWarrior

0

使用8字节值(64位),您将拥有2^64个可能的结果。这相当多,但明显少于GUID,后者具有2 ^ 128个可能的值。

您可以做一些简单的事情:

        // generate 8 byte random value
        Random rnd = new Random();
        byte[] bytes = new byte[8];
        rnd.NextBytes(bytes);

        // displaying the value
        string myRndID = BitConverter.ToString(bytes).Replace("-", "");
        Console.WriteLine(myRndID);

例如:

XXXX           YY        ZZ
----           --        --
Random Value   Node ID   Days since epoch (of your definition)

然后:

Cat XXXX, YY and ZZ bytes together to create your pseudo-guID.

但这种方法仅使用随机数生成。您可以从GUID算法(当前和过去)中获取一些提示,并将其中的某些8个字节填充为节点ID值或DateTime散列之类的内容,再结合随机值以降低发生冲突的风险。

尽管如此,冲突的可能性仍然存在,如果您最终使用8字节伪guID,则应定义处理冲突的流程。


0
GUID 的目的是要“全球”唯一,这意味着任何人都不太可能使用与其他对象已经使用的相同的唯一标识符,因此您愿意将其用于业务。比我聪明的人已经确定,16个字节加上正确的算法足以实现这一点。由于8个字节只能给您提供16个字节所能提供的极小一部分可能性,因此我不建议使用8字节 GUID。
但是,如果您真的想要,您可以像这样做:
public struct SmallGuid
{
    byte FirstByte;
    byte SecondByte;
    ...
}

然后,您可以为这些字节生成随机值,或利用真正的 Guid类,并从中取出一半的字节来填充您的SmallGuid。


请问,Stripling,你能告诉我更多的细节吗? - Linney
@Linney:需要更多关于哪个方面的细节? - StriplingWarrior
关于你的结构体SmallGuid,你能否告诉我更多关于如何生成这个小型GUID的细节? - Linney

0
你可以使用Guid.NewGuid().ToByteArray()并将其通过某些哈希算法运行,得到8字节(= 64位)的结果大小。
编辑: 有一种由Google开发的哈希算法返回64位(请参见http://code.google.com/p/cityhash/),可用于Guid.NewGuid().ToString()。

0

请参见GUID是全球唯一的,但GUID的子字符串不是

哈希GUID可能有效(但我不确定),但更好的想法是根据您所知道的系统约束,受GUID算法启发并基于自己的算法来生成ID,例如:

  • 如果您知道只会在少数几个系统上生成ID,则可以缩短GUID的MAC地址部分。
  • 同样,如果您假设您的应用程序将在100年后消失,则可以缩短时间戳部分。
  • 如果您只有一个算法,则不需要算法标识符。
  • 如果您还知道不会太快地生成它们,则可以缩短“紧急唯一标识符位”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接