2012-05-28 198 views
3

我想通過erlang寫入excel文件。我用以下代碼編寫Excel文件通過Erlang寫入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)有什麼辦法使得辦公室(MS Office的或自由報辦公室)將自動解析它??。

2)是否有任何其他的方式來寫通過二郎的Excel工作表..?

回答

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編碼更好。你也可以用Erlang處理文件爲 .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文件的一個例子,在外殼

 
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

從以下鏈接下面的信息,它直接創建Excel數據並滿足您的要求:

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

3例

如何使用彗星 3.1彗星的例子詳細的例子

本章詳細介紹關於彗星使用的som示例;最簡單的和最先進的。

四個實施例中給出:

Browsing to a specified address 

Opening Excel, dumping some data, showing a graph 

Calling a function in a C++ library 

這些源代碼包含在分佈,在目錄彗星/例子。

的縮寫VB和VBA用於Visual Basic和Visual Basic應用程序。 3.2要求

第一示例需要Internet Explorer 4.0或更高版本。

實施例2需要Excel從辦公室97或Office 2000

最後一個例子可以運行,因爲它是,但修改COM庫時,Visual C++ 5.0或更高是必需的。 3.3示例一,打開瀏覽器到一個特定的URL

這個例子顯示瞭如何打開一個瀏覽器(Internet Explorer),並瀏覽它到一個特定的地址。

爲了獲得瀏覽器的COM接口,我們使用了諸如Microsoft Windows平臺SDK,Visual C和Visual Basic中包含的OLE/COM Object Viewer等工具。

檢查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 Object Viewer,並獲取Excel的IDL。有一個Excel類型庫可用。我們不需要它,因爲它很大。我們只需選擇所需的接口,即_Application,_Graph和_Range。我們還提取了一些枚舉,這些常量用於COM調用中的參數。

從二郎

首先調用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('[email protected]'). 

-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對象

要做。