【问题标题】:Writing Excel FIle through Erlang通过 Erlang 编写 Excel 文件
【发布时间】:2012-05-28 09:37:22
【问题描述】:

我正在尝试通过 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表格??

【问题讨论】:

    标签: excel erlang


    【解决方案1】:

    你必须写一个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编码更好。您也可以通过首先使用 excel 将文件转换/重新保存为 .csv , comma delimited file 在 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,Opaque)-> 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 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 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 文档。

    【讨论】:

      【解决方案2】:

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

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

      3 个例子

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

      本章详细描述了彗星使用的一些例子;最简单的在前,最先进的在后。

      给出四个例子:

      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 接口,我们使用了 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对象

      待办。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-10-27
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-04
        • 1970-01-01
        相关资源
        最近更新 更多