通过Erlang编写Excel文件

时间:2012-05-28 09:37:22

标签: excel erlang

我正在尝试通过erlang编写excel文件。我使用以下代码编写excel文件

-module(excel).
-export([start/1]).

start(Val)->
        case  file:open("office-test.xls",[append]) of
        {ok,Fd} -> io:format(" file created"),
                io:fwrite(Fd,"~p\t~p\t~p~n", ["Name","Date","Number"]),
                export(Fd,Val),
                file:close(Fd);
        {error,_} ->  io:format("~nerror in creation of file")
        end.


export(_,0)->
        ok;

export(Fd,Val) ->
        io:fwrite(Fd, "~p\t~p\t~p\t~n" ,["B123","2012/10/11 12:12:12","val"++integer_to_list(Val)]),
        export(Fd,Val-1).

能够成功写入,但是当我在LibreOffice中打开时。我起了一个弹出窗口,询问分开的数据。我不希望最终用户使用它。

1)有办公室(办公室或自由办公室)会自动解析它吗?

2)有没有其他方法可以通过erlang编写excel表格。??

2 个答案:

答案 0 :(得分:4)

你必须写一个CSV , Comma delimited text file。您必须使用.csv 文件扩展名保存它。您可以按行写入此文件行。确保每一行都以\r\n结尾。这个文件可以从excel中很好地阅读。

确保标题出现在第一行,如下所示:

Name,Sex,Project\r\n
Joe Armstrong,Male,Erlang\r\n
Klacke Wickstrom,Male,Yaws\r\n
Rusty R,Male,Nitrogen\r\n
Bill Gates,Male,\r\n
Muzaaya Joshua,Male,ZeePay\r\n
此外,文件编码很重要。 ANSI编码更好。您也可以通过首先使用excel将文件转换/重新保存为.csv , comma delimited file来处理Erlang中的Excel文件。
然后使用 csv file parser module
%%% --- 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).

如何使用此模块从Excel解析csv文件。我们上面简单的csv文件的例子,在shell

C:\Windows\System32>erl
Eshell V5.9  (abort with ^G)
1> ForEachLine = fun(Line,Buffer)-> io:format("Line: ~p~n",[Line]),Buffer end.
#Fun<erl_eval.12.111823515>
2> InitialBuffer = [].
[]
3> csv:parse("E:/erlang_projects.csv",ForEachLine,InitialBuffer).
Line: ["Name","Sex","Project"]
Line: ["Joe Armstrong","Male","Erlang"]
Line: ["Klacke Wickstrom","Male","Yaws"]
Line: ["Rusty R","Male","Nitrogen"]
Line: ["Bill Gates","Male",[]]
Line: ["Muzaaya Joshua","Male","ZeePay"]
{ok,[]}
4> ForEachLine2 = fun(Line,Buffer)-> io:format("Line: ~p~n",[Line]),[Line|Buffer] end.
#Fun<erl_eval.12.111823515>
5> csv:parse("E:/erlang_projects.csv",ForEachLine2,InitialBuffer).
Line: ["Name","Sex","Project"]
Line: ["Joe Armstrong","Male","Erlang"]
Line: ["Klacke Wickstrom","Male","Yaws"]
Line: ["Rusty R","Male","Nitrogen"]
Line: ["Bill Gates","Male",[]]
Line: ["Muzaaya Joshua","Male","ZeePay"]
{ok,[["Muzaaya Joshua","Male","ZeePay"],
     ["Bill Gates","Male",[]],
     ["Rusty R","Male","Nitrogen"],
     ["Klacke Wickstrom","Male","Yaws"],
     ["Joe Armstrong","Male","Erlang"],
     ["Name","Sex","Project"]]}
6>

因此,您可以稍后使用此模块来解析Excel中的csv文件。现在,只学习如何逐行编写csv文件,阅读文件章节中的实用Erlang编程手册或erlang文档。

答案 1 :(得分:-1)

以下信息来自以下链接,它直接创建excel数据并满足您的要求:

http://www.erlang.org/documentation/doc-5.0.1/lib/comet-1.0/doc/html/ch_examples.html

3个例子

关于如何使用Comet的详细示例 3.1彗星例子

本章详细介绍了关于Comet用法的som示例;最简单的,最先进的。

给出了四个例子:

Browsing to a specified address

Opening Excel, dumping some data, showing a graph

Calling a function in a C++ library

这些的源代码包含在发行版中,目录为comet / examples。

缩写VB和VBA用于Visual Basic和Visual Basic for Applications。 3.2要求

第一个示例要求安装Internet Explorer 4.0或更高版本。

示例2需要Office 97或Office 2000中的Excel。

最后一个示例可以按原样运行,但要修改COM库,则需要Visual C ++ 5.0或更高版本。 3.3示例一,打开浏览器到特定URL

此示例显示如何打开浏览器(Internet Explorer),并将其导航到特定地址。

要获取浏览器的COM接口,我们使用OLE / COM对象查看器等工具,该工具包含在Microsoft的Windows平台SDK,Visual C和Visual Basic中。

检查Internet Explorer的界面,我们发现了一些我们需要的东西。首先,我们需要类ID。然后我们需要创建和使用浏览器所需的功能和属性的名称和参数列表。

由于启动浏览器不是一项性能关键任务,我们可以使用最慢,最安全的方式从Erlang中完成。这意味着将erl_com作为端口进程启动,并使用IDispatch接口访问Internet Explorer。

虽然Internet Explorer提供双接口(即同时具有方法表和IDispatch接口的接口),但IDispatch接口更安全,更慢。给它一个错误的参数列表,返回错误代码,而不是核心转储。

要使用COM对象,我们必须启动服务器(启动端口)并启动一个线程。然后我们可以创建对象,并用它做我们想做的事。

为了能够使用常量,我们将源放在一个模块中,而不是在Erlang shell中以交互方式调用它。

-module(win_browse).

-include("erl_com.hrl").

-export([open/1, example/0]).
open(Url) ->
    {ok, Pid}= erl_com:start_process(),
    T= erl_com:new_thread(Pid),
    Obj= erl_com:create_dispatch(T, "InternetExplorer.Application", 
                                 ?CLSCTX_LOCAL_SERVER),
    erl_com:invoke(Obj, "Navigate", [Url]),
    erl_com:property_put(Obj, "Visible", true),
    Obj.

example() ->
    open("www.erlang.org").

Internet Explorer应用程序有一个调度接口,用于实现IWebBrowser接口。有很多方法。我们使用Navigate方法打开特定URL,使用Visible属性显示浏览器。 (默认情况下,浏览器创建为不可见,就像COM中使用的其他Microsoft程序一样。) 3.4示例二,在Excel中制作图表

在此示例中,我们还启动了Excel应用程序的实例。我们使用程序名称&#34; Excel.Application&#34;,可以使用它来代替类ID。这将选择已安装的Excel; Office 97或Office 2000中的Excel。

使用Excel执行任何操作的最简单方法是首先录制VBA宏。生成的VBA宏如图1所示。手动重写该宏以使其更简单。我们尝试一下,结果如图2所示。

现在,要将其执行到Erlang中,我们有两个选择:要么我们可以使用来自Erlang的COM调用VB代码作为子例程,要么我们可以在Erlang中重新实现VB宏。由于这是用户指南,我们当然会选择后者。

要访问接口,我们使用OLE / COM对象查看器,并获取Excel的IDL。有一个Excel类型库可用。我们不希望所有这一切,因为它是巨大的。我们只需选择所需的接口,即_Application,_Graph和_Range。我们还提取了一些枚举,这些枚举是用于COM调用中的参数的常量。

从Erlang调用COM时有一些棘手的问题

首先,VB隐式处理COM接口的释放。 Erlang和COM不会这样做,因此我们必须为我们获得的每个接口调用erl_com:release / 1。例如,我们从属性_Application.Range获得的每个_Range都必须被释放。我们在辅助函数data_to_column / 3中执行此操作。

其次,当返回一个接口时,它将作为整数返回。该整数实际上是erl_com_drv端口程序中包含的接口数组的索引。在erl_com中调用函数时,我们必须同时提供pid和线程号,因此有一个辅助函数erl_com :: package_interface / 2,它使用给定的线程或其他接口重新打包接口整数。但是,当将接口作为参数提供给COM函数时(通过erl_com:call或erl_com:invoke),接口应该转换为指针,这是通过COM类型的元组表示法完成的:{vt_unknown,Interface}。

启动Excel时,我们执行一系列Excel命令来输入数据并绘制图形。这些命令是从我们使用Excel的标准宏录制器获得的VBA宏转换而来的。

我们使用Excel命令所需的一些常量。这些是从Excel界面的Visual Basic代码生成中获取的。尽管可以使用COM从Excel中获取这些内容,但erl_com尚不支持此功能。 (未来版本将包括代码生成,这将大大简化使用大型COM接口。

-module(xc).
-author('jakob@erix.ericsson.se').

-include("erl_com.hrl").

%% enum XlChartFormat
-define(XlPieExploded, 69).
-define(XlPie, 5).

%% enum XlChartLocation
-define(xlLocationAsNewSheet, 1).
-define(xlLocationAsObject, 2).
-define(xlLocationAutomatic, 3.


%% enum XlRowCol
-define(xlColumns, 2).
-define(xlRows, 1).


-export([populate_area/4, f/3, make_graph/6, sample1/0]).

to_cell_col(C) when C > 26 ->
        [C / 26 + 64, C rem 26 + 64];
to_cell_col(C) ->
        [C+64].

populate_area(E, _, _, []) ->
        ok;
populate_area(E, Row, Col, [Data | Resten]) ->
        Cell= to_cell_col(Col)++integer_to_list(Row),
        io:format(" ~s ~n ", [Cell]),
        N= erl_com:property_get(E, "range", [Cell]),
        Range= erl_com:package_interface(E, N),
        erl_com:property_put(Range, "Value", Data),
        erl_com:release(Range),
        populate_area(E, Row+1, Col, Resten).

f(E, _, []) ->
        ok;
f(E, Startcell, [Data | Resten]) ->
        {R, C}= Startcell,
        Cell= "R"++integer_to_list(R)++"C"++integer_to_list(C),
        io:format(" ~p ~n ", [Cell]),
        f(E, {R+1, C}, Resten).

make_graph(E, Row1, Col1, Row2, Col2, Title) ->
        Charts = erl_com:package_interface(E, erl_com:property_get(E, "Charts")),
        erl_com:invoke(Charts, "Add"),
        ActiveChart= erl_com:package_interface(E, erl_com:property_get
                                               (E, "ActiveChart")),
        erl_com:property_put(ActiveChart, "ChartType", {vt_i4, ?XlPieExploded}),
        erl_com:invoke(ActiveChart, "Location", [{vt_i4, ?xlLocationAsObject}, 
                                                 "Sheet1"]),
        Chart= erl_com:package_interface(E, erl_com:property_get(E, "ActiveChart")),
        R= to_cell_col(Col1)++integer_to_list(Row1)++":"
         ++to_cell_col(Col2)++integer_to_list(Row2),
        io:format(" ~s ~n ", [R]),
        Range= erl_com:property_get(E, "Range", [R]),
        erl_com:invoke(Chart, "SetSourceData", [{vt_unknown, Range}, 
                                                {vt_i4, ?xlColumns}]),
        erl_com:property_put(Chart, "HasTitle", true),
        ChartTitle= erl_com:package_interface(E, erl_com:property_get
                                              (Chart, "ChartTitle")),
        erl_com:property_put(ChartTitle, "Caption", Title).
        %erl_com:release(erl_com:package_interface(E, Range)),
        %erl_com:release(ActiveChart),
        %erl_com:release(Charts).

sample1() ->
        {ok, Pid}= erl_com:start_process(),
        T= erl_com:new_thread(Pid),
        E= erl_com:create_dispatch(T, "Excel.Application", ?CLSCTX_LOCAL_SERVER),
        erl_com:property_put(E, "Visible", true),
        Wb= erl_com:package_interface(T, erl_com:property_get(E, "Workbooks")),
        erl_com:invoke(Wb, "Add"),
        populate_area(E, 1, 1, ["Erlang", "Java", "C++"]),
        populate_area(E, 1, 2, ["25", "100", "250"]),
        make_graph(E, 1, 1, 3, 2, "Programming errors, by programming language"),
        {T, E, Wb}.

3.5示例三,在C ++中调用COM对象

待完成。