1

我想将 csv 文件中的数据存储在 mnesia 数据库中(特别是在名为“ user ”的表中)

我在这个论坛中找到了这种解决方案:

创建名为csv.erl 的文件:

%%% --- csv parser in Erlang. ------
%%% To help process large csv files without loading them into
%%% memory. Similar to the xml parsing technique of SAX

-module(csv).
-compile(export_all).

parse(FilePath,ForEachLine,Opaque)->
    case file:open(FilePath,[read]) of
        {_,S} ->
            start_parsing(S,ForEachLine,Opaque);
        Error -> Error
    end.

start_parsing(S,ForEachLine,Opaque)->
    Line = io:get_line(S,''),
    case Line of
        eof -> {ok,Opaque};
        "\n" -> start_parsing(S,ForEachLine,Opaque);
        "\r\n" -> start_parsing(S,ForEachLine,Opaque);
        _ -> 
            NewOpaque = ForEachLine(scanner(clean(clean(Line,10),13)),Opaque),
            start_parsing(S,ForEachLine,NewOpaque)
    end.

scan(InitString,Char,[Head|Buffer]) when Head == Char -> 
    {lists:reverse(InitString),Buffer};
scan(InitString,Char,[Head|Buffer]) when Head =/= Char ->
    scan([Head|InitString],Char,Buffer);
scan(X,_,Buffer) when Buffer == [] -> {done,lists:reverse(X)}.
scanner(Text)-> lists:reverse(traverse_text(Text,[])).

traverse_text(Text,Buff)->
    case scan("",$,,Text) of
        {done,SomeText}-> [SomeText|Buff];
        {Value,Rem}-> traverse_text(Rem,[Value|Buff])
    end.

clean(Text,Char)-> 
    string:strip(string:strip(Text,right,Char),left,Char).

创建功能测试:

test()->

    ForEachLine = fun(Line,Buffer)-> io:format("Line: ~p~n",[Line]),Buffer end,

 InitialBuffer = [],

 csv:parse("/home/include/user.csv",ForEachLine,InitialBuffer).

但是此解决方案仅在 Erlang 控制台中显示数据(它显示 csv 文件中的每一行),但我的目标是将 csv 文件中的这些行存储在用户表中。

我已经创建了用户记录

-record(user, {id, firstname, lastname, birthday}).

将行从 csv 文件注册到用户表,我尝试使用

test()->

    ForEachLine = fun(Line,Buffer)-> io:format("Line: ~p~n",[Line]),Buffer end,

 InitialBuffer = [],

 csv:parse("/home/test/user.csv",ForEachLine,InitialBuffer),



   F = fun() ->
         Line=#user{},
         mnesia:write(Line),                               
         {ok}

     end,
     {atomic, Val} = mnesia:transaction(F),
     Val.

但是这个函数不会在用户表中插入数据

4

2 回答 2

2

你需要做几件事:

  • 在 mnesia 中创建一个模式来保存您的数据。那就是创造一个#user{}记录。
  • 把你的台词做成类型的记录R = #user{}
  • mnesia:write(R)在事务内部调用。为了使其更快,您可以在同一个事务中批量写入几次,或者简单地使用mnesia:dirty_write(R).
于 2013-01-26T14:26:17.040 回答
1

我是这个模块的作者。现在,您已传递给库以应用于它找到的每一行的功能对象,您可以根据自己的喜好对其进行自定义。例如:

F = 乐趣(线,_)->
        [Id,Firstname, Lastname, Birthday] = 线,
        U = #用户{
            身份证=身份证,
            名字 = 名字,
            姓氏 = 姓氏,
            生日=生日
        },
        mnesia:dirty_write(U),
        []
    结尾。

现在,请记住,如果文件的格式非常好.csv,这意味着每一行都与下一行相同,那么模式匹配就可以了,就像我在Fun上面所做的那样。通常,标题(文件中的第一行.csv)将显示整个数据集中的列,以便前面的行可以使用第一行作为模板。

把它放在一边,看看这条线,然后把它Line转换成一个 erlang 记录。您可以将该Buffer变量用作计数器,因为它随后会在每次Fun调用时更新。请记住,Fun退出时带有更新的Buffer变量,以便它可以将其应用于.csv文件中的下一行。因此,如果您recursion非常了解,您的 Buffer 变量可以是一个整数,从开始,然后在每次调用Zero结束时递增它。Fun这是一个例子:

F = 乐趣(线,计数器)->
        [Id,Firstname, Lastname, Birthday] = 线,
        U = #用户{
            身份证=身份证,
            名字 = 名字,
            姓氏 = 姓氏,
            生日=生日
        },
        mnesia:dirty_write(U),
        计数器 + 1
    结尾。
在上面的示例中,您Buffer现在只是一个计数器。这将自动显示从文件插入到 mnesia 的记录总数.csv

请记住 erlang 数据结构的通用性。你的Fun,只要它被构造成带有两个变量,第一个是 Line,你可以将它自定义为任何东西。在 内部Fun,您甚至可以将 发送Line到另一个 erlang 节点或 erlang 进程。像这样:

F = 乐趣(线路,服务器)->
        [Id,Firstname, Lastname, Birthday] = 线,
        U = #用户{
            身份证=身份证,
            名字 = 名字,
            姓氏 = 姓氏,
            生日=生日
        },
        服务器 !{from_csv,U}
        服务器
    结尾。
在上面的示例中,您的Buffer变量是一个常量,它是您将从文件中发送每条记录的进程的Pid或。总之, Buffer 变量可能会或可能不会在每次后续调用下一行时更新,这取决于您。您可能只是在. 然后,每个都必须进行模式匹配,然后转换为适当的。Registered Name.csvFunFunLineMnesia record
主要答案编辑

现在,在库模块中,我假设delimiter您的.csv文件是comma. 在那个模块中,我想让你看一下函数:traverse_text/2,它目前看起来像这样:
traverse_text(Text,Buff)->
    case scan("",$,,Text) of
        {done,SomeText}-> [SomeText|Buff];
        {Value,Rem}-> traverse_text(Rem,[Value|Buff])
    结尾。

请更改上述功能以反映您DELIMITER的 . 例如,如果delimiter是 a semi-colon ( ; ),则该函数变为:

traverse_text(Text,Buff)->
    case scan("",$;,Text) of
        {done,SomeText}-> [SomeText|Buff];
        {Value,Rem}-> traverse_text(Rem,[Value|Buff])
    结尾。

因此,如果您delimiter有所不同,只需按照我在上面显示的那样更改该功能(我希望您看到符号在哪里,在哪里看到dollar sign, followed by your actual delimiter)。然后,重新编译并重新加载该模块。如果您遇到更多挑战,请告诉我。

于 2013-01-27T14:11:37.707 回答