【问题标题】:Erlang: Writing mnesia table to .csv one record per lineErlang:将 mnesia 表写入 .csv 每行一条记录
【发布时间】:2016-09-18 22:01:43
【问题描述】:

我有一个 Mnesia 表,其格式如下:

-record(state, {key, tuple, state, timestamp, fin_from}).

条目如下所示(使用ets:tab2list(Tab) 阅读):

[{state,{80,43252,tcp,tcp_syn_received,{192,168,101,5},{192,168,101,89}},
        {80,43252,tcp,{192,168,101,5},{192,168,101,89}},
        tcp_syn_received,1463850419221,undefined},
 {state,{80,41570,tcp,tcp_syn_received,{192,168,101,5},{192,168,101,89}},
        {80,41570,tcp,{192,168,101,5},{192,168,101,89}},
        tcp_syn_received,1463850403214,undefined},
...]

我想将这些数据写入 .csv 文件,每行一个条目 - 首选以下格式:

state,80,43252,tcp,tcp_syn_received,192.168.101.5,192.168.101.89,80,43252,tcp,192.168.101.5,192.168.101.89,tcp_syn_received,1463850419221,undefined
state,80,41570,tcp,tcp_syn_received,192.168.101.5,192.168.101.89,80,41570,tcp,192.168.101.5,192.168.101.89,tcp_syn_received,1463850419221,undefined

undefined 之后应该有一个换行符。 我尝试使用以下代码(Content = ets:tab2list(states)):

do_logging_async(File, Format, Content, Append)->
F = fun() ->
    file:write_file(File, io_lib:fwrite(Format, [Content]), [Append])
end,
spawn(F).

但是,我无法获得与我的输出类似的任何内容。 之后应使用 R 评估数据。

更新:关键是逐行读取表格并用~w而不是~p解析它。我最终得到了以下解决方案(它产生的输出略有不同,但是冗余数据较少):

do_state_logging(File, EtsAsList) ->
% write header (columnnames)
file:write_file(File, io_lib:fwrite("~w,~w,~w,~w,~w,~w,~w,~w~n", [record,dstPort,srcPort,proto,dstIP,srcIP,state,timestamp]),[append]),
case EtsAsList of
    [] ->
        ok;
    _ ->
        F = fun({Record,_Key, 
            [P1, P2, Proto, {D_Ip_1,D_Ip_2,D_Ip_3,D_Ip_4}, {S_Ip_1,S_Ip_2,S_Ip_3,S_Ip_4}],
            State, Timestamp, _}) -> 
            file:write_file(File, io_lib:fwrite("~w,", [Record]),[append]),
            file:write_file(File, io_lib:fwrite("~w,~w,~w,", [P1,P2,Proto]),[append]),
            file:write_file(File, io_lib:fwrite("~w.~w.~w.~w,", [D_Ip_1,D_Ip_2,D_Ip_3,D_Ip_4]), [append]),
            file:write_file(File, io_lib:fwrite("~w.~w.~w.~w,", [S_Ip_1,S_Ip_2,S_Ip_3,S_Ip_4]), [append]),
            file:write_file(File, io_lib:fwrite("~w,", [State]),[append]),
            file:write_file(File, io_lib:fwrite("~w", [Timestamp]),[append]),
            file:write_file(File, ["\n"],[append]) 
        end,
        lists:foreach(F, EtsAsList)
    end,
    io:format("Finished logging of statetable to file: ~p~n" , [File]).

感谢促使我提出这个想法的答案。

【问题讨论】:

  • 是否可以将 ets 值保存为列表而不是元组?即[80,43252,tcp,tcp_syn_received,[192,168,101,5],[192,168,101,89]], [80,43252,tcp,[192,168,101,5],[192,168,101,89]], tcp_syn_received,1463850419221,undefined]。因为那样的话,将每个展平记录写成一行会更简单。
  • 是的,我可以这样做。但是之后如何解析单行(和列表)?

标签: csv erlang export-to-csv mnesia


【解决方案1】:

假设您将 ets 记录值更改为列表而不是元组,您可以使用此代码将 ETS 表写入文件。

do_logging_async(File, EtsAsList) ->
    F = fun({Key, Value}) -> 
        file:write_file(File, [atom_to_list(Key) ++ ","],[append]),
        write_value(File,lists:flatten(Value)),
        file:write_file(File, ["\n"],[append]) 
    end,
    lists:foreach(F,EtsAsList).


write_value(_File, []) -> ok;
write_value(File, [H|T]) ->
    case is_integer(H) of
        true -> file:write_file(File, [integer_to_list(H)],[append]);
        false -> file:write_file(File, [atom_to_list(H)],[append])
    end,
    case T=:=[] of
        true -> ok;
        false -> file:write_file(File, [","],[append])
    end,
    write_value(File,T).

do_logging_async/2 获取每个 {Key, Value} 对。首先,它将Key 写入文件,然后在Value 上运行write_value/2,在每对的末尾写入\n

write_value/2 获取扁平值列表(假设它是一个仅包含整数和原子的扁平列表)并将其写入文件。

【讨论】:

  • 我将其调整为我的格式:do_logging_async(File, EtsAsList) -> lists:foreach(fun({state, Key, Key_no_state, State, Timestamp, _Val4}) -> %io:format("Writing during this Iteration: { Key, Key_no_state, State, Timestamp, _Val4} ~p~n",[{Key, Key_no_state, State, Timestamp, _Val4}]), file:write_file(File, [Key ++ ","],[append]),... write_value(File,lists:flatten([Timestamp])), file:write_file(File, ["\n"],[append]) end, EtsAsList). 但是,只写入时间戳。 file:write_file() return {error, badargs}.. 不知道如何继续..
  • 您需要将您的 ets {Key, Value} 对更改为 {state, [Key, Key_no_state, State, Timestamp, Fin_from]},然后按原样使用我的代码,它应该可以工作。
猜你喜欢
  • 2017-06-10
  • 2017-03-25
  • 2018-09-18
  • 1970-01-01
  • 2013-05-20
  • 2019-06-05
  • 2021-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多