GUID
GUID (全局唯一标识符)
全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符。GUID主要用于在拥有多个节点、多台计算机的网络或系统中。在理想情况下,任何计算机和计算机集群都不会生成两个相同的GUID。GUID 的总数达到了2^128(3.4×10^38)个,所以随机生成两个相同GUID的可能性非常小,但并不为0。GUID一词有时也专指微软对UUID标准的实现。
在理想情况下,任何计算机和计算机集群都不会生成两个相同的GUID。随机生成两个相同GUID的可能性是非常小的,但并不为0。所以,用于生成GUID的算法通常都加入了非随机的参数(如时间),以保证这种重复的情况不会发生。
在 Windows 平台上,GUID 广泛应用于微软的产品中,用于标识如注册表项、类及接口标识、数据库、系统目录等对象。
中文名 全局唯一标识符 外文名 GUID,Globally Unique Identifier 类 型 数字标识符 作用于 多节点、多计算机的网络或系统
目录
▪ 格式
1 特点
2 争议
3 程序
▪ VB
▪ C++
▪ Delphi
▪ C#
▪ Java
▪ OC
▪ Pascal
▪ 易语言
▪ PHP
▪ Excel VBA
格式
GUID 的格式为“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”,其中每个 x 是 0-9 或 a-f 范围内的一个4位十六进制数。例如:6F9619FF-8B86-D011-B42D-00C04FC964FF 即为有效的 GUID 值。
特点
★需要GUID的时候,可以完全由算法自动生成,不需要一个权威机构来管理。
★GUID理论上能产生全球唯一的值,对于以后的数据导入很方便。
争议
由于GUID值产生的潜在弊端已经引起了保密性提倡者的关注。1999年3月,美国联邦商务委员会接到要求,对微软的GUID值使用进行调查。争议主要涉及Office 97和Office 2000文档对GUID值的使用。Office文档,如Word文件或Excel电子数据表,所使用的GUID值对用户是不可见的。但有很多报道宣称,文档的作者是可以通过GUID值的跟踪查到的,即使作者已经采用特殊方法,他们还是可以被追踪到。 为了回应上述问题,微软已经发布了一个Office 97修补版SR2,它禁止了GUID功能的使用,并且还可以将现存文档的GUID去除。
潜在的对Intel处理器序列号滥用的问题与上述GUID值的问题本质是一样的。
程序
VB
Option Explicit
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4(8) As Byte
End Type
Private Declare Function CoCreateGuid Lib "ole32.dll" (pguid As GUID) As Long
Private Declare Function StringFromGUID2 Lib "ole32.dll" (rguid As Any, ByVal lpstrClsId As Long, ByVal cbMax As Long) As Long
Private Function GUIDGen() As String '生成GUID
Dim uGUID As GUID
Dim sGUID As String
Dim bGUID() As Byte
Dim lLen As Long
Dim RetVal As Long
lLen = 40
bGUID = String(lLen, 0)
CoCreateGuid uGUID '把结构转换为一个可显示的字符串
RetVal = StringFromGUID2(uGUID, VarPtr(bGUID(0)), lLen)
sGUID = bGUID
If (Asc(Mid$(sGUID, RetVal, 1)) = 0) Then RetVal = RetVal - 1
GUIDGen = Left$(sGUID, RetVal)
End Function
C++
#include <objbase.h>
#include <stdio.h>
//--生成GUID
const char* newGUID()
{
static char buf[64] = {0};
GUID guid;
if (S_OK == ::CoCreateGuid(&guid))
{
_snprintf(buf, sizeof(buf)
, "{%08X-%04X-%04x-%02X%02X-%02X%02X%02X%02X%02X%02X}"
, guid.Data1
, guid.Data2
, guid.Data3
, guid.Data4[0], guid.Data4[1]
, guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5]
, guid.Data4[6], guid.Data4[7]
);
}
return (const char*)buf;
}
int main(int argc, char* argv[])
{
//--COM
CoInitialize(NULL);
printf(newGUID());
printf("\n");
//--COM
CoUninitialize();
return 0;
}
Delphi
uses ActiveX;
function ctGUID:string;
var
id:TGUID;
begin
CoCreateGuid(id);
Result:=GUIDToString(id);
end;
C#
using System;
namespace GUID测试
{
class Program
{
static void Main(string[] args)
{
//产生一个新的GUID并输出
Console.WriteLine(System.Guid.NewGuid());
Console.ReadKey();
}
}
}
Java
import java.util.UUID;
public class guid {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
UUID uuid = UUID.randomUUID();
System.out.println(".{"+uuid.toString()+"}");
}
}
OC
NSString * get_uuid()
{
CFUUIDRef uuid_ref = CFUUIDCreate(NULL);
CFStringRef uuid_string_ref= CFUUIDCreateString(NULL, uuid_ref);
CFRelease(uuid_ref);
NSString *uuid = [NSStringstringWithString:(NSString*)uuid_string_ref];
CFRelease(uuid_string_ref);
return uuid;
}
Pascal
【注:貌似上面的Delphi无法在free pascal下使用】
Function Guid_Gen:ansistring;
Var
s:string;
i:longint;
Begin
s:='0123456789abcdef';
//8-4-4-4-12
Guid_Gen:='xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx';
for i:=1 to length(Guid_Gen) do begin
if Guid_Gen[i]='x' then Guid_Gen[i]:=s[Random(16)+1];
end;
End;
易语言
.版本 2
.DLL命令 CoCreateGuid, , "ole32", "CoCreateGuid"
.参数 guid, 字节集
.版本 2
.子程序 生成新的GUID, 文本型
.局部变量 guid, 字节集
.局部变量 a, 长整数型
.局部变量 b, 整数型
.局部变量 c, 整数型
.局部变量 s, 文本型
.局部变量 i, 整数型
guid = 取空白字节集 (16)
CoCreateGuid (guid)
a = 取字节集数据 (取字节集左边 (guid, 4), #长整数型, )
b = 取字节集数据 (取字节集中间 (guid, 5, 2), #整数型, )
c = 取字节集数据 (取字节集中间 (guid, 7, 2), #整数型, )
s = “”
s = s + 取文本右边 (“00000000” + 取十六进制文本 (a), 8) + “-”
s = s + 取文本右边 (“0000” + 取十六进制文本 (b), 4) + “-”
s = s + 到小写 (取文本右边 (“0000” + 取十六进制文本 (c), 4)) + “-” ' 第三部分中的字母为小写字母
.计次循环首 (8, i)
s = s + 取文本右边 (“00” + 取十六进制文本 (guid [i + 8]), 2)
.如果真 (i = 2)
s = s + “-”
.如果真结束
.计次循环尾 ()
返回 (“{” + s + “}”)
PHP
public function create_guid(){ $charid = strtoupper(md5(uniqid(mt_rand(), true))); $hyphen = chr(45);// "-" $uuid = substr($charid, 6, 2).substr($charid, 4, 2).substr($charid, 2, 2).substr($charid, 0, 2).$hyphen .substr($charid, 10, 2).substr($charid, 8, 2).$hyphen .substr($charid,14, 2).substr($charid,12, 2).$hyphen .substr($charid,16, 4).$hyphen .substr($charid,20,12); return $uuid; }
Excel VBA
Function GetGuidToString() As String
GetGuidToString = LCase(Mid$(CreateObject("Scriptlet.TypeLib").GUID, 2, 36))
End Function
“简单证明GUID(全局唯一标识符)并不唯一”
GUID是什么,大家理所当然地应该都知道(百度百科介绍的GUID)。在.net framework中,微软为开发者提供了一个GUID结构,这个结构想必很多人在开发中应该已经用过,下面我们再来看一下它的备注说明:
“GUID 是一个 128 位整数(16 字节),可用于所有需要唯一标识符的计算机和网络。此标识符重复的可能性非常小。”
注意红色的标注,标识符是有重复的可能的,只不过重复的概率小之又小。到这里你我可能都会产生疑问,重复的可能性到底有多小呢?如何证明有重复呢?在stackoverflow上,一个善于思考勇于发现并提出问题挑战权威的C#开发先驱抛出了一个有趣的问答题:“Simple proof that GUID is not unique”(本文的标题就是按照英文原文标题直译过来的)。
在英文原文中,提问者说他想在一个测试程序中简单证明一下GUID并不唯一,然后给出了如下代码实现:
1
2
3
BigInteger begin = new BigInteger((long)0);
BigInteger end = new BigInteger("340282366920938463463374607431768211456",10); //2^128
for(begin; begin<end; begin++) Console.WriteLine(System.Guid.NewGuid().ToString());
令人感到遗憾的是,“it's not working”(实际上,拷贝这份代码到VS中,编译无法通过,BigInteger的构造函数根本不存在,for循环的地方写得也不对,估计是伪代码)。
接着,我们看到了投票次数最多的正确答案:
GuidCollisionDetector
楼猪第一次看到代码的时候,精神抖擞热情洋溢地分析如下:
1、定义一个字节数组reserveSomeRam,分配一块内存空间;
2、通过HashSet对象填充GUID,直至内存不足,通过GC的KeepAlive和Collect方法,释放出预留给reserveSomeRam的内存空间,保证程序有继续运行的微小内存空间(此时,楼猪惊呼,好一段惊世骇俗奇技淫巧的NB代码啊);
3、通过两个for循环,配合并行库,通过HashSet的Contains函数证明新产生的GUID有可能产生重复(这里主要就是CPU运算的事情了,完全用不到reserveSomeRam那一块的内存,充分地利用了CPU和内存,这种思想这种境界真是令人感到匪夷所思望尘莫及,牛)。
但是看到代码中的“throw new ApplicationException("Guids collided! Oh my gosh!");”和Console.WriteLine("Umm... why hasn't the universe ended yet?");,楼猪有一种穿越的感觉。
接着楼猪仔细看了一下这个正确答案的正文回答的细节,发现这家伙从头到尾都是一种煞有介事一本正经的口气,又是版权,又是要钱,又是坐着时光机回到2010年2月28号获得技术支持的…恍然大悟,kao,真是TM的太好玩太会扯淡了。
忍耐不住好奇,怀着强烈的求知欲望,楼猪看完了所有回答,有人用数学方法证明…祝你好运;有人寄希望于未来的量子计算机显灵;有人提议组织志愿者现在就开始他们伟大的136年证明之旅;有人提议升级显卡,NVIDIA 可能会贷款赞助这个历史性的计算;有人说他可以帮忙,已经被证明了,他曾经获得过某一个GUID数字……楼猪久违地又蛋疼了。
比较起来,个人感觉还是这个回答比较靠谱:
Well if the running time of 83 billion years does not scare you, think that you will also need to store the generated GUIDs somewhere to check if you have a duplicate; storing 2^128 16-byte numbers would only require you to allocate 4951760157141521099596496896 terabytes of RAM upfront, so imagining you have a computer which could fit all that and that you somehow find a place to buy terabyte DIMMs at 10 grams each, combined they will weigh more than 8 Earth masses, so you can seriously shift it off the current orbit, before you even press "Run". Think twice!
大致意思就是说,跑完证明程序,需要大概830亿年时间和4951760157141521099596496896 TB(1TB=1024GB)的内存空间(假设每个DIMM内存有10克重,所有的内存换算成重量,大概是8个地球的重量之和)。从看似有限而又无限的时间和空间上证明,GUID重复这种概率发生的可能性实在是太太太小了,可以认为基本不可能。有一个回复说,“Personally, I think the "Big Bang" was caused when two GUIDs collided.”,即:两个GUID重复之日,宇宙大爆炸之时。
实际上,楼猪现在也是这么认为的。
您有好的方法证明GUID会重复吗?
GUID是一个128位长的数字,一般用16进制表示。算法的核心思想是结合机器的网卡、当地时间、一个随机数来生成GUID。从理论上讲,如果一台机器每秒产生10000000个GUID,则可以保证(概率意义上)3240年不重复。
UUID是1.5中新增的一个类,在java.util下,用它可以产生一个号称全球唯一的ID
Java代码 收藏代码
import java.util.UUID;
public class Test {
public static void main(String[] args) {
UUID uuid = UUID.randomUUID();
System.out.println (uuid);
}
}
编译运行输出:
07ca3dec-b674-41d0-af9e-9c37583b08bb
两种方式生成guid 与uuid
需要comm log 库
Java代码 收藏代码
/**
* @author Administrator
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
public class RandomGUID extends Object {
protected final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
.getLog(getClass());
public String valueBeforeMD5 = "";
public String valueAfterMD5 = "";
private static Random myRand;
private static SecureRandom mySecureRand;
private static String s_id;
private static final int PAD_BELOW = 0x10;
private static final int TWO_BYTES = 0xFF;
/*
* Static block to take care of one time secureRandom seed.
* It takes a few seconds to initialize SecureRandom. You might
* want to consider removing this static block or replacing
* it with a "time since first loaded" seed to reduce this time.
* This block will run only once per JVM instance.
*/
static {
mySecureRand = new SecureRandom();
long secureInitializer = mySecureRand.nextLong();
myRand = new Random(secureInitializer);
try {
s_id = InetAddress.getLocalHost().toString();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
/*
* Default constructor. With no specification of security option,
* this constructor defaults to lower security, high performance.
*/
public RandomGUID() {
getRandomGUID(false);
}
/*
* Constructor with security option. Setting secure true
* enables each random number generated to be cryptographically
* strong. Secure false defaults to the standard Random function seeded
* with a single cryptographically strong random number.
*/
public RandomGUID(boolean secure) {
getRandomGUID(secure);
}
/*
* Method to generate the random GUID
*/
private void getRandomGUID(boolean secure) {
MessageDigest md5 = null;
StringBuffer sbValueBeforeMD5 = new StringBuffer(128);
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
logger.error("Error: " + e);
}
try {
long time = System.currentTimeMillis();
long rand = 0;
if (secure) {
rand = mySecureRand.nextLong();
} else {
rand = myRand.nextLong();
}
sbValueBeforeMD5.append(s_id);
sbValueBeforeMD5.append(":");
sbValueBeforeMD5.append(Long.toString(time));
sbValueBeforeMD5.append(":");
sbValueBeforeMD5.append(Long.toString(rand));
valueBeforeMD5 = sbValueBeforeMD5.toString();
md5.update(valueBeforeMD5.getBytes());
byte[] array = md5.digest();
StringBuffer sb = new StringBuffer(32);
for (int j = 0; j < array.length; ++j) {
int b = array[j] & TWO_BYTES;
if (b < PAD_BELOW)
sb.append('0');
sb.append(Integer.toHexString(b));
}
valueAfterMD5 = sb.toString();
} catch (Exception e) {
logger.error("Error:" + e);
}
}
/*
* Convert to the standard format for GUID
* (Useful for SQL Server UniqueIdentifiers, etc.)
* Example: C2FEEEAC-CFCD-11D1-8B05-00600806D9B6
*/
public String toString() {
String raw = valueAfterMD5.toUpperCase();
StringBuffer sb = new StringBuffer(64);
sb.append(raw.substring(0, 8));
sb.append("-");
sb.append(raw.substring(8, 12));
sb.append("-");
sb.append(raw.substring(12, 16));
sb.append("-");
sb.append(raw.substring(16, 20));
sb.append("-");
sb.append(raw.substring(20));
return sb.toString();
}
// Demonstraton and self test of class
public static void main(String args[]) {
for (int i=0; i< 100; i++) {
RandomGUID myGUID = new RandomGUID();
System.out.println("Seeding String=" + myGUID.valueBeforeMD5);
System.out.println("rawGUID=" + myGUID.valueAfterMD5);
System.out.println("RandomGUID=" + myGUID.toString());
}
}
}
同样
Java代码 收藏代码
UUID uuid = UUID.randomUUID();
System.out.println("{"+uuid.toString()+"}");
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成UUID的API。UUID按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。关于UUID这个标准使用最普遍的是微软的GUID(Globals Unique Identifiers)。
GUID是一个128位长的数字,一般用16进制表示。算法的核心思想是结合机器的网卡、当地时间、一个随即数来生成GUID。从理论上讲,如果一台机器每秒产生10000000个GUID,则可以保证(概率意义上)3240年不重复。
复制代码 代码如下:
package com.cn.str;
import java.util.UUID;
/**
* Create GUID
* @author Administrator
*
*/
public class CreateGUID {
public static final String GenerateGUID(){
UUID uuid = UUID.randomUUID();
return uuid.toString();
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(GenerateGUID());
}
}
UUID是1.5中新增的一个类,在java.util下,用它可以产生一个号称全球唯一的ID