通过Erlang编写Excel文件

我正在尝试通过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打开。 我popup了一个popup窗口询问数据分开。 我不希望最终用户在其上工作。

1)有什么办法可以让办公室(ms office或libre office)自动parsing它。

2)是否有任何其他方式通过erlang写入excel表单?

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

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

 姓名,性别,项目\ r \ n
乔·阿姆斯特朗,男,Erlang \ r \ n
 Klacke Wickstrom,男,Yaws \ r \ n
生锈的R,雄性,氮\ r \ n
比尔·盖茨,男,\ r \ n
 Muzaaya Joshua,男,ZeePay \ r \ n

另外,文件编码很重要。 ANSI编码更好。 你也可以用Erlang处理Excel文件,首先使用excel将文件转换/重新保存为.csv , comma delimited file
然后使用这个csv file parser module

 erlang中%%% --- csv分析器。  ------
 %%%帮助处理大型csv文件而不加载它们
 %%%内存。 类似于SAX的xmlparsing技术 
-module(CSV)。 -compile(export_all)。
parsing(文件path,ForEachLine,不透明) - > 大小写文件:打开(FilePath,[read])的 {_,S} - > start_parsing(S,ForEachLine,不透明); 错误 - >错误 结束。

start_parsing(S,ForEachLine,不透明) - > Line = io:get_line(S,''),
案例行 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) 结束。
扫描(InitString,Char,[Head | Buffer])当Head == Char - > {列表:反向(InitString),缓冲}; 扫描(InitString,Char,[Head | Buffer])当Head = / = Char - >时 扫描([杆头| InitString],字符,缓冲液); 当缓冲区== [] - > {done,列出:reverse(X)}时,扫描(X,_,Buffer) 扫描仪(文本) - >列表:reverse(traverse_text(Text,[]))。
traverse_text(文字,浅黄色) - > 案例扫描(“”,$ ,, Text)的 {done,SomeText} - > [SomeText | Buff]; {Value,Rem} - > traverse_text(Rem,[Value | Buff]) 结束。
干净(文字,字符) - > string:带材(string:带材(文本,右,CHAR),左,CHAR)。

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

 C:\ Windows \ System32下> ERL
 Eshell V5.9(放弃^ 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:[“Joe Armstrong”,“Male”,“Erlang”]
 Line:[“Klacke Wickstrom”,“Male”,“Yaws”]
行:[“Rusty R”,“Male”,“Nitrogen”]
行:[“比尔盖茨”,“男”,[]]
 Line:[“Muzaaya Joshua”,“Male”,“ZeePay”]
 {好,[]}
 4> ForEachLine2 = fun(Line,Buffer) - > io:format(“Line:〜p〜n”,[Line]),[Line | Buffer]结束。
 #Fun <erl_eval.12.111823515>
 5> csv:parse(“E:/erlang_projects.csv”,ForEachLine2,InitialBuffer)。
行:[“姓名”,“性别”,“项目”]
 Line:[“Joe Armstrong”,“Male”,“Erlang”]
 Line:[“Klacke Wickstrom”,“Male”,“Yaws”]
行:[“Rusty R”,“Male”,“Nitrogen”]
行:[“比尔盖茨”,“男”,[]]
 Line:[“Muzaaya Joshua”,“Male”,“ZeePay”]
 {ok,[[“Muzaaya Joshua”,“Male”,“ZeePay”],
      [“比尔盖茨”,“男”,[]],
      [“Rusty R”,“Male”,“Nitrogen”],
      [“Klacke Wickstrom”,“男性”,“Yaws”],
      [“乔·阿姆斯特朗”,“男”,“Erlang”],
      [ “姓名”, “性别”, “工程项目”]]}
 6>

所以稍后你可以使用这个模块从Excel中parsing你的csv文件。 现在,学习如何逐行写入一个csv文件,在文件章节或erlang文档中阅读实用的Erlang编程书籍。

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

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或更高版本。

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

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

这个例子展示了如何打开一个浏览器(Internet Explorer),并浏览到一个特定的地址。

为了获得浏览器的COM接口,我们使用了Microsoft Windows平台SDK,Visual C和Visual Basic中包含的OLE / COM Object Viewer等工具。

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

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

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

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

为了能够使用常量,我们把源代码放在一个模块中,而不是在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中制作graphics

在这个例子中,我们也启动了Excel应用程序的一个实例。 我们使用程序名“Excel.Application”,它可以用来代替类ID。 这将select安装的Excel; 来自Office 97或Office 2000的Excel。

使用Excel最简单的方法是首先录制一个VBAmacros。 生成的VBAmacros如图1所示。这个macros被手动重写了一下,使其更简单。 我们尝试一下,结果如图2所示。

现在,为了实现Erlang,我们有两个select:要么使用来自Erlang的COM调用VB代码作为子程序,要么用Erlang重新实现VBmacros。 既然这是用户指南,我们当然select后者。

为了获得接口,我们使用OLE / COM对象查看器,并获取Excel的IDL。 有一个Exceltypes的库可用。 我们不想要这么多,因为它很大。 我们只需select所需的接口,即_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,用给定的线程或其他接口重新包装接口整数。 但是,当将接口作为parameter passing给COM函数(通过erl_com:call或erl_com:invoke)时,接口应该转换为一个指针,该指针由COMtypes的元组表示法完成:{vt_unknown,Interface}。

当Excel启动时,我们执行一系列Excel命令来input数据并绘制graphics。 这些命令是从我们用Excel的标准macroslogging器获得的VBAmacros中翻译的。

我们使用Excel命令所需的一些常量。 这些都是从Excel接口的Visual Basic代码生成中提取的。 虽然这些可以从Excel中使用COM获取,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对象

要做。

Interesting Posts