首页 文章资讯内容详情

MongoDB C Driver使用教程

2026-05-31 4 花语

本文内容纲要:

-MongoDBCDriver使用教程 -0.安装 -1.启动MongoDB -2.进行连接 -查看更多 -3.创建BSON文件 -1、追加BSON -2、使用BCON -3、从JSON创建BSON -4.基本的CRUD(增删查改)操作 -1、插入文档 -2、查找文档 -3、更新文档 -4、删除文档 -5、统计文档 -5.执行命令 -6.线程 -7.今后的步骤

MongoDBCDriver使用教程

转载请注明出处http://www.cnblogs.com/oloroso/

本指南提供简介MongoDBC驱动程序。

在CAPI的详细信息,请参阅API文档.

原文来自http://api.mongodb.com/c/current/tutorial.html

目录

MongoDBCDriver使用教程

0.安装

1.启动MongoDB

2.进行连接

查看更多

3.创建BSON文件

1、追加BSON 2、使用BCON 3、从JSON创建BSON

4.基本的CRUD(增删查改)操作

1、插入文档 2、查找文档 3、更新文档 4、删除文档 5、统计文档

5.执行命令

6.线程

7.今后的步骤

0.安装

有关特定的平台上安装MongoDBC驱动程序的详细说明,请参阅安装指南.

MongoDBC驱动程序的安装

编译http://www.cnblogs.com/oloroso/p/5740431.html

1.启动MongoDB

要运行本教程中的例子,MongoDB必须安装运行在本地主机(localhost),且使用默认端口27017。要检查MongoDB是否启动并运行,使用MongoDBShell连接就知道了。

$mongo--hostlocalhost--port27017 MongoDBshellversion:3.0.6 connectingto:localhost:27017/test >

2.进行连接

MongoDBCDriver程序通过mongoc_client_t提供了一种简便的访问MongoDB的方法(与集群配置无关的)。

它满足透明地连接到独立的服务器,副本集和分片集群上的需求。一旦建立了连接,数据库和集合的句柄可以通过结构mongoc_database_t和mongoc_collection_t分别得到。然后可以通过这些句柄执行MongoDB操作。

在应用程序的启动后,先调用mongoc_init(),libmongoc的任何其他功能才能正确使用,并需要在退出之前调用mongoc_cleanup()。当创建client、database和server的句柄后,需要在使用完后调用适当的销毁函数。

下面的示例建立一个独立的服务器上的本地主机的连接,并执行一个简单的命令。有关数据库操作的详细信息可以查看CRUD操作和执行命令部分。连接到副本集和分片集群的例子可以在高级连接页面查看。

connect.c

#include<bson.h> #include<bcon.h> #include<mongoc.h> int main(intargc, char*argv[]) { mongoc_client_t*client; mongoc_database_t*database; mongoc_collection_t*collection; bson_t*command, reply, *insert; bson_error_terror; char*str; boolretval; /* *初始化libmongocs */ mongoc_init(); /* *创建一个新的client实例 */ client=mongoc_client_new("mongodb://localhost:27017"); /* *获取数据库"db_name"和集合"coll_name"的句柄 */ database=mongoc_client_get_database(client,"db_name"); collection=mongoc_client_get_collection(client,"db_name","coll_name"); /* *执行操作。此处以执行ping数据库,以json格式打印结果。并执行一个插入操作。 */ //执行命令操作(ping) command=BCON_NEW("ping",BCON_INT32(1)); retval=mongoc_client_command_simple(client,"admin",command,NULL,&reply,&error); if(!retval){ fprintf(stderr,"%s\n",error.message); returnEXIT_FAILURE; } //获取json形式的结果 str=bson_as_json(&reply,NULL); printf("%s\n",str); //打印输出 //插入操作命令 insert=BCON_NEW("hello",BCON_UTF8("world")); if(!mongoc_collection_insert(collection,MONGOC_INSERT_NONE,insert,NULL,&error)){ fprintf(stderr,"%s\n",error.message); } //释放资源 bson_destroy(insert); bson_destroy(&reply); bson_destroy(command); bson_free(str); /* *释放拥有的句柄并清理libmongoc */ mongoc_collection_destroy(collection); mongoc_database_destroy(database); mongoc_client_destroy(client); mongoc_cleanup(); return0; }

在unix系统中,代码可以编译和运行像这样︰

$gcc-oconnectconnect.c$(pkg-config--cflags--libslibmongoc-1.0) $./connect {"ok":1.000000}

或者,如果pkg配置不可用,可以手动管理路径和库文件。

$gcc-oconnectconnect.c-I/usr/local/include-lmongoc-1.0-lbson-1.0 $./connect {"ok":1.000000}

对于Windows用户,可以编译和运行下面的命令代码。(这假定MongoDBCDriver程序安装在C:\mongo-c-driver;安装在其他位置的根据需要更改包含目录。)

C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0connect.c C:\>connect {"ok":1.000000}

查看更多

高级的连接 教程 mongoc_client_get_collection() mongoc_client_get_database() mongoc_client_new()

3.创建BSON文件

BSON文档(Documents)是存储在MongoDB的数据格式。CDriver程序使用libbson来创建BSON文档。

有几种方式来构建它们:1、追加key-value(键值对);2、使用BCON;3、解析JSON字符串。

1、追加BSON

BSON文档,在代码中使用bson_t表示。可以将构造一个字段,使用libbson的append功能进行追加。

#include<bson.h> int main(intargc, char*argv[]) { bson_t*document; bson_tchild; char*str; document=bson_new(); /* *追加{"hello":"world"}到document. *传递-1作为长度参数,告诉libbson自己去计算字符串长度. */ bson_append_utf8(document,"hello",-1,"world",-1); /* *方便使用的,这个宏与上面是等效的。 */ BSON_APPEND_UTF8(document,"hello","world"); /* *开始一个子文档 */ BSON_APPEND_DOCUMENT_BEGIN(document,"subdoc",&child); BSON_APPEND_UTF8(&child,"subkey","value"); bson_append_document_end(document,&child); /* *打印这个BSON对象,以json字符串格式。 */ str=bson_as_json(document,NULL); printf("%s\n",str); bson_free(str); /* *清理已分配的bsondocuments. */ bson_destroy(document); return0; }

请参阅libbson文档的所有可附加到bson_t的类型.

2、使用BCON

BCON是BSONC对象表示法的简称,是另一种以更接近预定的格式构建BSON文档的方式。它有在类型安全上比BSON的append功能弱,但使用的代码更少。

#include<bcon.h> #include<bson.h> #include<stdio.h> int main(intargc, char*argv[]) { bson_t*doc; char*str; doc=BCON_NEW("name",BCON_UTF8("BabeRuth"), "statistics","{", "batting_average",BCON_DOUBLE(.342), "hits",BCON_INT32(2873), "home_runs",BCON_INT32(714), "rbi",BCON_INT32(2213), "}", "nicknames","[", BCON_UTF8("theSultanofSwat"), BCON_UTF8("theBambino"), "]"); str=bson_as_json(doc,NULL); printf("%s\n",str); bson_free(str); bson_destroy(doc); return0; }

请注意,BCON可以创建数组、子文档以及任意字段。

3、从JSON创建BSON

JSON字符串可以通过bson_new_from_json创建单个BSON文档。

若要从一个JSON文档序列初始化BSON,使用bson_json_reader_t。 #include<bson.h> int main(intargc, char*argv[]) { bson_error_terror; bson_t*bson; char*string; constchar*json="{\"hello\":\"world\"}"; bson=bson_new_from_json((constuint8_t*)json,-1,&error); if(!bson){ fprintf(stderr,"%s\n",error.message); returnEXIT_FAILURE; } string=bson_as_json(bson,NULL); printf("%s\n",string); bson_free(string); return0; }

更多的信息

教程

4.基本的CRUD(增删查改)操作

本节演示如何使用CDriver程序与MongoDB进行交互的基本知识。

插入文档 查找文档 更新的文档 删除文档 统计文档

1、插入文档

若要向集合中插入文件,首先通过mongoc_client_t获取mongoc_collection_t的句柄。然后使用mongoc_collection_insert()将BSON文档添加到集合。

本示例将插入记录到数据库"mydb"和集合"mycoll"。

当完成后,确保分配的结构使用他们各自的销毁函数进行释放。

insert.c

#include<bson.h> #include<mongoc.h> #include<stdio.h> int main(intargc, char*argv[]) { mongoc_client_t*client; mongoc_collection_t*collection; bson_error_terror; bson_oid_toid; bson_t*doc; //初始化libmongoc mongoc_init(); //连接到数据库,并获取集合句柄 client=mongoc_client_new("mongodb://localhost:27017/"); collection=mongoc_client_get_collection(client,"mydb","mycoll"); //创建一个bson文档,并追加键值对数据 doc=bson_new(); bson_oid_init(&oid,NULL); BSON_APPEND_OID(doc,"_id",&oid); BSON_APPEND_UTF8(doc,"hello","world"); //将bson文档插入到集合 if(!mongoc_collection_insert(collection,MONGOC_INSERT_NONE,doc,NULL,&error)){ fprintf(stderr,"%s\n",error.message); } //释放资源 bson_destroy(doc); mongoc_collection_destroy(collection); mongoc_client_destroy(client); //清理libmongoc mongoc_cleanup(); return0; }

对代码进行编译并运行︰

Linux和Unix下: $gcc-oinsertinsert.c$(pkg-config--cflags--libslibmongoc-1.0) $./insert

Windows下:

C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0insert.c C:\>insert

若要验证插入成功与否,使用MongoDBShell进行查看。

$mongo MongoDBshellversion:3.0.6 connectingto:test >usemydb switchedtodbmydb >db.mycoll.find() {"_id":ObjectId("55ef43766cb5f36a3bae6ee4"),"hello":"world"} >

更多的信息

基本操作 mongoc_collection_insert()

2、查找文档

若使用CDirver程序去查询MongoDB集合,请使用函数mongoc_collection_find()](http://api.mongodb.com/c/current/mongoc_collection_find.html)。将返回一个匹配的文档的cursor(游标)。

下面示例循环访问resultcursor(结果游标)并打印到为JSON字符串到标准输出。

请注意,mongoc_collection_find使用BSON文档作为查询说明符;

例如,{"color":"red"}将匹配所有文档中字段名为color且值为red的。空文档{}可以用于匹配的所有文件。

这第一个示例使用空查询说明符,来找到所有"mydb"数据库中"mycoll"集合的文档。

find.c

#include<bson.h> #include<mongoc.h> #include<stdio.h> int main(intargc, char*argv[]) { mongoc_client_t*client; mongoc_collection_t*collection; mongoc_cursor_t*cursor; constbson_t*doc; bson_t*query; char*str; mongoc_init(); client=mongoc_client_new("mongodb://localhost:27017/"); collection=mongoc_client_get_collection(client,"mydb","mycoll"); //query是一个空的BSON文档,用于做查询说明符的时候匹配所有文档。 query=bson_new(); //执行查询操作 cursor=mongoc_collection_find(collection,MONGOC_QUERY_NONE,0,0,0,query,NULL,NULL); while(mongoc_cursor_next(cursor,&doc)){ str=bson_as_json(doc,NULL); printf("%s\n",str); bson_free(str); } bson_destroy(query); mongoc_cursor_destroy(cursor); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_cleanup(); return0; }

对代码进行编译和运行它︰

Linux和Unix下: $gcc-ofindfind.c$(pkg-config--cflags--libslibmongoc-1.0) $./find {"_id":{"$oid":"55ef43766cb5f36a3bae6ee4"},"hello":"world"}

Windows下:

C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0find.c C:\>find {"_id":{"$oid":"55ef43766cb5f36a3bae6ee4"},"hello":"world"}

若要查找特定的文档,将添加指定的查询说明符。本示例将添加对BSON_APPEND_UTF8()的调用来寻找匹配{"hello":"world"}的所有文档。

find-specific.c

#include<bson.h> #include<mongoc.h> #include<stdio.h> int main(intargc, char*argv[]) { mongoc_client_t*client; mongoc_collection_t*collection; mongoc_cursor_t*cursor; constbson_t*doc; bson_t*query; char*str; mongoc_init(); client=mongoc_client_new("mongodb://localhost:27017/"); collection=mongoc_client_get_collection(client,"mydb","mycoll"); //query在这里将添加一个键值对,查询的时候将只查询出匹配上的结果 query=bson_new(); BSON_APPEND_UTF8(query,"hello","world"); cursor=mongoc_collection_find(collection,MONGOC_QUERY_NONE,0,0,0,query,NULL,NULL); while(mongoc_cursor_next(cursor,&doc)){ str=bson_as_json(doc,NULL); printf("%s\n",str); bson_free(str); } bson_destroy(query); mongoc_cursor_destroy(cursor); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_cleanup(); return0; }

编译运行

$gcc-ofind-specificfind-specific.c$(pkg-config--cflags--libslibmongoc-1.0) $./find-specific {"_id":{"$oid":"55ef43766cb5f36a3bae6ee4"},"hello":"world"} C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0find-specific.c C:\>find-specific {"_id":{"$oid":"55ef43766cb5f36a3bae6ee4"},"hello":"world"}

更多的信息

基本操作 mongoc_collection_find()

3、更新文档

这段代码是使用mongoc_collection_update()来更新的文档字段的示例。

下面的示例使用"mydb"数据库,将文档插入到"mycoll"集合。然后利用其_id字段,更新文档的值(key对应的value),并添加一个新的字段(updated)。

update.c

#include<bcon.h> #include<bson.h> #include<mongoc.h> #include<stdio.h> int main(intargc, char*argv[]) { mongoc_collection_t*collection; mongoc_client_t*client; bson_error_terror; bson_oid_toid; bson_t*doc=NULL; bson_t*update=NULL; bson_t*query=NULL; mongoc_init(); client=mongoc_client_new("mongodb://localhost:27017/"); collection=mongoc_client_get_collection(client,"mydb","mycoll"); //初始化一个对象ID bson_oid_init(&oid,NULL); doc=BCON_NEW("_id",BCON_OID(&oid)/*使用上面初始化的oid*/, "key",BCON_UTF8("old_value")); //插入到数据库中 if(!mongoc_collection_insert(collection,MONGOC_INSERT_NONE,doc,NULL,&error)){ fprintf(stderr,"%s\n",error.message); gotofail; } //注意,这里使用的oid是之前插入一样的 query=BCON_NEW("_id",BCON_OID(&oid)); update=BCON_NEW("$set","{", "key",BCON_UTF8("new_value")/*修改值*/, "updated",BCON_BOOL(true) /*添加的字段*/, "}"); //执行update操作。这个操作将使用update的内容去替换之前插入到数据库中的doc的内容 if(!mongoc_collection_update(collection,MONGOC_UPDATE_NONE,query,update,NULL,&error)){ fprintf(stderr,"%s\n",error.message); gotofail; } fail: if(doc) bson_destroy(doc); if(query) bson_destroy(query); if(update) bson_destroy(update); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_cleanup(); return0; }

对代码进行编译和运行它︰

Linux和Unix下: $gcc-oupdateupdate.c$(pkg-config--cflags--libslibmongoc-1.0) $./update

Windows下:

C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0update.c C:\>update {"_id":{"$oid":"55ef43766cb5f36a3bae6ee4"},"hello":"world"}

若要验证插入成功与否,使用MongoDBShell进行查看。

$mongo MongoDBshellversion:3.0.6 connectingto:test >usemydb switchedtodbmydb >db.mycoll.find({"updated":true}) {"_id":ObjectId("55ef549236fe322f9490e17b"),"updated":true,"key":"new_value"} >

更多的信息

基本操作 mongoc_collection_find_and_modify() mongoc_collection_update()

4、删除文档

本示例说明了使用mongoc_collection_remove()来删除文档。

下面的代码插入一个示例文档到数据库"mydb"的"mycoll"集合。然后,它会删除所有与{"hello":"world"}相匹配的文档。

delete.c

#include<bson.h> #include<mongoc.h> #include<stdio.h> int main(intargc, char*argv[]) { mongoc_client_t*client; mongoc_collection_t*collection; bson_error_terror; bson_oid_toid; bson_t*doc; mongoc_init(); client=mongoc_client_new("mongodb://localhost:27017/"); collection=mongoc_client_get_collection(client,"test","test"); doc=bson_new(); bson_oid_init(&oid,NULL); BSON_APPEND_OID(doc,"_id",&oid); BSON_APPEND_UTF8(doc,"hello","world"); //添加hello字段,值为world //插入文档 if(!mongoc_collection_insert(collection,MONGOC_INSERT_NONE,doc,NULL,&error)){ fprintf(stderr,"Insertfailed:%s\n",error.message); } bson_destroy(doc); doc=bson_new(); BSON_APPEND_OID(doc,"_id",&oid); //这里只添加了_id字段 //这里与上面描述的有点不一致,因为这里匹配的只是上面插入的,而不是含hello字段,且值为world的 //如果按照描述的话,这里应该改为BSON_APPEND_UTF8(doc,"hello","world")才行。 //执行删除操作。这里只能匹配_id字段,也就只能删除上面插入的文档 if(!mongoc_collection_remove(collection,MONGOC_REMOVE_SINGLE_REMOVE,doc,NULL,&error)){ fprintf(stderr,"Deletefailed:%s\n",error.message); } bson_destroy(doc); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_cleanup(); return0; }

对代码进行编译和运行它︰

Linux和Unix下: $gcc-odeletedelete.c$(pkg-config--cflags--libslibmongoc-1.0) $./delete

Windows下:

C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0delete.c C:\>delete

使用MongoDBShell证明文件已成功删除。

$mongo MongoDBshellversion:3.0.6 connectingto:test >usemydb switchedtodbmydb >db.mycoll.count({"hello":"world"}) 0 >

更多的信息

基本操作 mongoc_collection_remove()

5、统计文档

这里的标题应该改为文档计数会更合理。

计数MongoDB集合中的文档数目类似于执行查找操作。此示例在数据库"mydb"中"mycoll"集合中获取与{"hello":"world"}相匹配的文档的数目。

count.c

#include<bson.h> #include<mongoc.h> #include<stdio.h> int main(intargc, char*argv[]) { mongoc_client_t*client; mongoc_collection_t*collection; bson_error_terror; bson_t*doc; int64_tcount; mongoc_init(); client=mongoc_client_new("mongodb://localhost:27017/"); collection=mongoc_client_get_collection(client,"mydb","mycoll"); //doc用于计数时候做匹配 doc=bson_new_from_json((constuint8_t*)"{\"hello\":\"world\"}",-1,&error); //进行统计操作 count=mongoc_collection_count(collection,MONGOC_QUERY_NONE,doc,0,0,NULL,&error); if(count<0){ fprintf(stderr,"%s\n",error.message); }else{ printf("%"PRId64"\n",count); } bson_destroy(doc); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_cleanup(); return0; }

对代码进行编译和运行它︰

Linux和Unix下:

$gcc-ocountcount.c$(pkg-config--cflags--libslibmongoc-1.0) $./count 1

Windows下:

C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0count.c C:\>count 1

更多的信息

基本操作 mongoc_collection_count() Tutorial

5.执行命令

驱动程序提供在客户端执行MongoDB命令操作数据库和集合结构的helperfunctions(辅助函数)。这些函数返回的cursor游标。这些函数的*_simple变体形式返回指示成功或失败的布尔值。

本示例针对数据库"mydb"中的"mycoll"集合执行collStats(获取集合状态信息)命令。

executing.c

#include<bson.h> #include<bcon.h> #include<mongoc.h> #include<stdio.h> int main(intargc, char*argv[]) { mongoc_client_t*client; mongoc_collection_t*collection; bson_error_terror; bson_t*command; bson_treply; char*str; mongoc_init(); client=mongoc_client_new("mongodb://localhost:27017/"); collection=mongoc_client_get_collection(client,"mydb","mycoll"); //创建命令(命令也是一个BSON文档) command=BCON_NEW("collStats",BCON_UTF8("mycoll")); //执行命令。注意,这里使用的是_simple变体形式 if(mongoc_collection_command_simple(collection,command,NULL,&reply,&error)){ str=bson_as_json(&reply,NULL); printf("%s\n",str); bson_free(str); }else{ fprintf(stderr,"Failedtoruncommand:%s\n",error.message); } bson_destroy(command); bson_destroy(&reply); mongoc_collection_destroy(collection); mongoc_client_destroy(client); mongoc_cleanup(); return0; }

对代码进行编译和运行它︰

Linux和Unix下: $gcc-oexecutingexecuting.c$(pkg-config--cflags--libslibmongoc-1.0) $./executing {"ns":"mydb.mycoll","count":1,"size":48,"avgObjSize":48,"numExtents":1,"storageSize":8192, "lastExtentSize":8192.000000,"paddingFactor":1.000000,"userFlags":1,"capped":false,"nindexes":1, "indexDetails":{},"totalIndexSize":8176,"indexSizes":{"_id_":8176},"ok":1.000000}

Windows下:

C:\>cl.exe/IC:\mongo-c-driver\include\libbson-1.0/IC:\mongo-c-driver\include\libmongoc-1.0executing.c C:\>executing {"ns":"mydb.mycoll","count":1,"size":48,"avgObjSize":48,"numExtents":1,"storageSize":8192, "lastExtentSize":8192.000000,"paddingFactor":1.000000,"userFlags":1,"capped":false,"nindexes":1, "indexDetails":{},"totalIndexSize":8176,"indexSizes":{"_id_":8176},"ok":1.000000}

更多的信息

教程 mongoc_client_command() mongoc_client_command_simple() mongoc_collection_command() mongoc_collection_command_simple() mongoc_database_command() mongoc_database_command_simple()

6.线程

MongoDBCDriver程序在绝大多数相关操作是线程未知的。这意味着它是由程序员来保证线程安全性。

然而,mongoc_client_pool_t(mongoc客户端池)是线程安全,用于以线程安全的方式获取mongoc_client_t。然后后从pool中检索client,clientstructure应调用线程持有。该线程完成后,client应该放回池中。

#include<mongoc.h> #include<pthread.h> #defineN_THREADS10 //线程工作函数 staticvoid* worker(void*data){ mongoc_client_pool_t*pool=data; mongoc_client_t*client; //从客户端池中获取一个客户端 client=mongoc_client_pool_pop(pool); /*Dosomething...*/ //用完后需要还回客户端池 mongoc_client_pool_push(pool,client); returnNULL; } int main(intargc, char*argv[]) { mongoc_client_pool_t*pool; mongoc_uri_t*uri; pthread_tthreads[N_THREADS]; mongoc_init(); uri=mongoc_uri_new("mongodb://localhost/"); //创建客户端池 pool=mongoc_client_pool_new(uri); //循环创建线程 for(i=0;i<N_THREADS;i++){ pthread_create(&threads[i],NULL,worker,pool); } //等待各个线程结束 for(i=0;i<N_THREADS;i++){ pthread_join(threads[i],NULL); } //是否客户端池 mongoc_client_pool_destroy(pool); mongoc_uri_destroy(uri); mongoc_cleanup(); return0; }

7.今后的步骤

若要查找有关高级主题的信息,请浏览CDriver程序指南或官方MongoDB文档的其余部分.

常见的问题的帮助,请参阅疑难解答页。要报告一个bug或请求一个新的功能,请按照这里的说明

更多的信息

基本的疑难解答 教程

本文内容总结:MongoDBCDriver使用教程,0.安装,1.启动MongoDB,2.进行连接,查看更多,3.创建BSON文件,1、追加BSON,2、使用BCON,3、从JSON创建BSON,4.基本的CRUD(增删查改)操作,1、插入文档,2、查找文档,3、更新文档,4、删除文档,5、统计文档,5.执行命令,6.线程,7.今后的步骤,

原文链接:https://www.cnblogs.com/oloroso/p/5733083.html