erlang 变量存储在哪里_[Erlang开发之路]十九、用ets和dets储存数据

ETS和DETS的介绍

ETS和DETS都是两个系统模块,可以用来储存海量的数据,ETS的全称是Erlang Term Storage(erlang 数据储存),而Dets就是加了个Disk,磁盘ETS,他们的任务相同,提供大型的KV(Key-Value)查询表,ETS比DETS高效,它储存在内存中,

一、ETS

表的类型

首先分为两个大类:

异键表(set):要求键是唯一的

异键表

有序异键表(ordered set):元组会被排序

同键表(bag):允许多个元素使用同一个键,但不能允许有键-值完全相同的元素存在

同键表

副本同键(duplicate bag)

表的操作

1.创建一个ETS表

-spec ets:new(TableName,[Option])-> TabeId when

TableName::atom().

Option:: [set | ordered_set | bag | duplicate bag,private | public | protected,named_table,{keypos,Pos}].

%% set | ordered_set | bag | duplicate bag 是表的类型上面有总结

%% private是创建一个私有表,只有主管进程(创建表的进程)才可以读写它

%% public是创建一个公共表,只要知道TableId就可以读写它

%% protected是创建一个受保护表,只有主管进程可以写它,其他进程只可以读

%% named_table 设置了这个选项之后,可以用TableName代替TableId对表进行操作

%% {keypos,Pos}以元组的Pos位置作为键所在的位置,通常为1

%% 当Option是一个空列表,采用默认值: [set,protected,{keypos,1}]

2.表的写入

-spec ets:insert(TableId,[tuple()])-> bool() when

%% TableId是表的标识符

%% [tuple()]是以拥有一个以上元素的元组为元素的列表,[{key1,V1},{key2,V2}],可以向表写入多个Key-Value

%% 举例:

ets:insert(TableId,[{key1,123,{test,666}},{key2,456,abc}]).

表对键是否相同的判断

这里要先介绍两种判断方法:

match

match相当于精确判断,不仅值要相同,类型也要相同,例如1.0和1 虽然值相同,但是1.0是float类型 而1是integer类型

compare equal

compare equal相当于模糊判断,值相同即可

Set类型的表采用match来判断键是否重复,ordered_set类型的表采用compare equal来判断

3.表的读取

-spec ets:lookup(TabId,Key)->[tuple()]

%% 返回一组符合要求的元组结果

除了使用lookup来查找,ets还提供了一些更为强大的查找方法:

-spec ets:match(TabId, Pattern) -> [Match]

%% Match可以是tuple中某些元素,也可以是全部元素

%% 举例

test()->

TableId=ets:new(etsTable,[bag]),

ets:insert(etsTable,{key,value1,value2}),

io:format("matchResult:~p~n",[getMatch(TableId,{key,_,'$1'})]),

io:format("matchResult:~p~n",[getMatch(TableId,{key,'$2','$1'})]),

io:format("matchResult:~p~n",[getMatch(TableId,'$1')]).

getMatch(TabId,Pattern)->

ets:match(TabId,Pattern).

%% 输出结果就是

%% [[value2]]

%% [[value2,value1]]

其中Pattern可以包含以下字符 1.一个绑定变量或者任意Erlang Term;

2.一个占位符'_',可以匹配任何Erlang Term;

3.一个变量符'$N' (N可以为0,1,2,3....),该变量指定了match方法需要返回tuple中哪些元素;

若Pattern中包含Key值,那么查找起来非常快速(相当于索引查询),否则需要全表遍历

我们除了可以一次性查找出所有满足匹配的tuples,也可以采用"分页查询"的方式查询,即每次只查询出部分结果,然后通过迭代查找出所有结果:

-spec ets:match(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'

%% Continuation变量保存了下一个分页的信息,要获取下一页时,只需要match(Continuation)即可获取下一页,当返回'$end_of_table'时没有下一页了

%% 例子:

test()->

TableId=ets:new(etsTable,[bag]),

ets:insert(etsTable,{key1,value1,value2}),

ets:insert(etsTable,{key1,value2,value1}),

{FirstMatch,Page2}=ets:match(TableId,{key1,'$1','$2'},1),%%一页一条记录

io:format("matchResult:~p~n",[FirstMatch])),

{SecondMatch,Page3}=ets:match(Page2),%%一页一条记录

io:format("matchResult:~p~n",[SecondMatch])),

Page3.

%% 输出结果:

%% matchResult:[[value2],[value1]]

%% matchResult:[[value1],[value2]]

%% '$end_of_table'

4.最后我们来看下ets table的遍历

-spec first(TableId) -> Key | '$end_of_table' %%用于获取表中第一个Key

-spec next(TableId, Key1) -> Key2 | '$end_of_table' %%用于获取Key1后面的Key

%%来个遍历获取{key,Value}的例子

listTable(TableId)->

case ets:first(TableId) of

'$end_of_table'->

io:format("啥都没有让我遍历个啥~n");

Key->

Result=ets:lookup(TableId,Key),

io:format("Key: ~p Value:~p ~n",[Key,Result]),

listTable(TableId,Key).

listTable(TableId,Key)->

case ets:next(TableId,Key) of

'$end_of_table'->

io:format("到尾了兄弟~n");

Key2->

Result=ets:lookup(TableId,Key),

io:format("Key: ~p Value:~p ~n",[Key2,Result]),

listTable(TableId,Key2).

ets的其他函数

-spec delete(Tab, Key) -> true

%删除表中某个KV

-spec delete(Tab) -> true

%删除整个表

-spec all() -> [Tab]

%获取目前所有表

-spec delete_all_objects(Tab) - > true

%删除ETS表选项卡中的所有对象。该操作保证是 原子的和隔离的。

-spec delete_object(Tab,Object) - > true

%从ETS表中删除确切的对象Object,保留具有相同键但具有其他差异的对象(对于类型包有用)。在duplicate_bag表中,将删除该对象的所有实例。

-spec file2tab(FileSrc) - > {ok,Tab} | {error,Reason}

%读取tab2file / 2或 tab2file / 3生成的文件,并创建相应的表Tab。相当于file2tab(Filename,[])。

-spec tab2file(Tab, Filename) -> ok | {error, Reason}

%保存table到File

%....后面太多了 看手册去吧

二、DETS

ETS把元组保存在内存里,而DETS把元组保存在磁盘上,它的最大文件大小是2GB,DETS文件必须先打开才可以操作,用完以后还要正确关闭。他们之间表的属性也不一样,DETS在打开文件时必须赋予一个全局名称,如果两个或者更多的进程以同一个名称和选项打开了文件,他们就会共享这个表,直到所有进程都关闭他,否则一直是打开状态

%拿例子说话

open(File)->

io:format("dets opened:~p~n",[File]),

Bool = filelib:is_file(File),

case dets:open_file(?MODULE,[{file,File}]) of

{ok,?MODULE}->

case Bool of

true->void;

false->ok=dets:insert(?MODULE,{free,1})

end,

true;

{error,Reason}->

io:format("cannot open dets table~n"),

exit({eDetsOpen,File,Reason})

end.

close()->

dets:close(?MODULE).

%这个例子是dets打开和关闭的例子,我们使用了模块名作为表名

filename2index(FileName) when is_binary(FileName)->

case dets:lookup(?MODULE,Filename) of

[]->

[{_,Free}]=dets:lookup(?MODULE,free),

ok=dets:insert(?MODULE,[{Free,FileName},{FileName,Free},{free,Free+1}]),

Free;

[{_,N}]->

N

end.

%这个例子就包含了读和写

手册内推荐阅读有关ETS和DETS的函数

基于模式获取和删除对象

ETS和DETS、以及ETS表和文件之间的互相转换

查看表的资源占用情况

遍历表内所有的元素

修复损坏的DETS表

让表可视化

ETS表的各种方法:

ets:all/0

获取所有的 ets 表

ets:delete/1

删除整张表

ets:delete/2

删除表里指定键的所有数据

ets:delete_all_objects/1

删除表里的所有数据

ets:delete_object/2

删除表里的指定数据

ets:file2tab/1

从一个文件读取一个 ETS 表

ets:first/1

获取 ETS 表里的第一个对象数据的键

ets:foldl/3

对 ETS 数据遍历循环操作

ets:fun2ms/1

把语法函数转为匹配规范的伪函数

ets:give_away/3

改变一个表的拥有者

ets:i/0

在输出端上打印显示所有 ETS 表的信息

ets:info/1

返回一个 ETS 表的信息

ets:info/2

返回给出的跟表相关的项的信息

ets:insert/2

向 ETS 表插入数据

ets:insert_new/2

向 ETS 表插入新数据

ets:is_compiled_ms/1

检测一个 Erlang 数据是否是一个有效已编译的匹配规范

ets:last/1

返回表里的最后一个键

ets:lookup/2

在 ETS 表里查出相应键的值

ets:lookup_element/3

返回 ETS 表里指定键的对象数据的第几个元素数据

ets:match/1 | ets:match/2 | ets:match/3

根据匹配模式匹配表里的对象数据

ets:match_delete/2 | ets:match_object/1 | ets:match_object/2 | ets:match_object/3

根据匹配模式删除表里的对象数据

ets:match_spec_compile/1

把一个匹配规范编译为它的内部表示形式

ets:match_spec_run/2

使用一个匹配规范来执行匹配操作

ets:member/2

判断表里面是否存在指定键的数据

ets:new/2

创建一个 ets 表

ets:next/2

返回表的下一个键

ets:prev/2

返回表的上一个键

ets:rename/2

重新给 ETS 表命名一个名字

ets:safe_fixtable/2

锁定一定 ETS 表使其可以安全遍历

ets:select/1

对 ETS 表里的数据进行匹配比对

ets:select_delete/2

根据匹配模式删除表里的对象数据

ets:tab2file/2 | ets:tab2file/2

把一个 ETS 表转储到一个文件里

ets:tab2list/1

返回一个 ETS 表的所有对象数据的列表

ets:to_dets/2

把内存里的 ETS 数据插入到磁盘上保存

ets:update_element/3

更新 ETS 表里指定键的对象数据的第几个元素数据

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值