3

我正在尝试通过 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)有什么办法可以让office(ms office或libre office)自动解析它。??

2)还有其他方法可以通过erlang编写excel表吗??

4

2 回答 2

4

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

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

姓名、性别、项目\r\n
Joe Armstrong,男,二郎\r\n
Klacke Wickstrom,男性,Yaws\r\n
Rusty R,男性,氮气\r\n
比尔·盖茨,男,\r\n
Muzaaya Joshua,男,ZeePay\r\n
此外,文件编码也很重要。ANSI编码更好。您也可以通过首先将文件转换/重新保存为.csv , comma delimited file使用 excel 来处理 Erlang 中的 Excel 文件。
然后用这个csv file parser module
%%% --- Erlang 中的 csv 解析器。------
%%% 帮助处理大型 csv 文件而不将它们加载到
%%% 记忆。类似于 SAX 的 xml 解析技术
-模块(csv)。 -编译(export_all)。
解析(文件路径,ForEachLine,不透明)-> 案例文件:open(FilePath,[read]) of {_,S} -> start_parsing(S,ForEachLine,不透明); 错误 -> 错误 结尾。

start_parsing(S,ForEachLine,不透明)-> Line = io:get_line(S,''),
case Line of eof -> {ok,不透明}; "\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) 结尾。
扫描(InitString,Char,[Head|Buffer]) 当 Head == Char -> {lists:reverse(InitString),Buffer}; 当 Head =/= Char -> 时扫描(InitString,Char,[Head|Buffer]) scan([Head|InitString],Char,Buffer); 当 Buffer == [] -> {done,lists:reverse(X)} 时扫描(X,_,Buffer)。 扫描仪(文本)-> 列表:反向(traverse_text(文本,[]))。
traverse_text(Text,Buff)-> case scan("",$,,Text) of {done,SomeText}-> [SomeText|Buff]; {Value,Rem}-> traverse_text(Rem,[Value|Buff]) 结尾。
清洁(文本,字符)-> 字符串:条(字符串:条(文本,右,字符),左,字符)。

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

C:\Windows\System32>erl
Eshell V5.9(使用 ^G 中止)
1> ForEachLine = fun(Line,Buffer)-> io:format("Line: ~p~n",[Line]),缓冲结束。
#Fun<erl_eval.12.111823515>
2> 初始缓冲区 = []。
[]
3> csv:parse("E:/erlang_projects.csv",ForEachLine,InitialBuffer)。
行:[“姓名”,“性别”,“项目”]
行:[“乔·阿姆斯特朗”,“男”,“二郎”]
线路:["Klacke Wickstrom","Male","Yaws"]
行:["Rusty R","Male","Nitrogen"]
行:[“比尔盖茨”,“男”,[]]
线路:["Muzaaya Joshua","Male","ZeePay"]
{行,[]}
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)。
行:[“姓名”,“性别”,“项目”]
行:[“乔·阿姆斯特朗”,“男”,“二郎”]
线路:["Klacke Wickstrom","Male","Yaws"]
行:["Rusty R","Male","Nitrogen"]
行:[“比尔盖茨”,“男”,[]]
线路:["Muzaaya Joshua","Male","ZeePay"]
{好的,[[“Muzaaya Joshua”,“Male”,“ZeePay”],
     [“比尔盖茨”,“男”,[]],
     [“生锈的 R”,“男性”,“氮气”],
     [“Klacke Wickstrom”,“男性”,“Yaws”],
     [“乔·阿姆斯特朗”,“男”,“二郎”],
     ["姓名","性别","项目"]]}
6>

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

于 2012-05-30T05:53:36.937 回答
-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 实例使用详解

本章详细介绍了 Comet 使用的一些示例;最简单的在前,最先进的在后。

给出了四个例子:

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 Object Viewer 等工具,该工具包含在 Microsoft 的 Windows Platform 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 应用程序的一个实例。我们使用程序名称“Excel.Application”,可以使用它来代替类 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对象

要完成。

于 2012-05-28T10:19:26.250 回答