在Ruby中高效地将Excel转换为CSV

10

我使用了 spreadsheet gem 来完成这个任务。它可以工作,但有时速度会非常慢。我甚至尝试了Roo gem,但它并没有改善性能。有更好的方法来完成这项工作吗?奇怪的是,同一份Excel中的某些工作表运行得更快,而有些工作表非常慢,甚至需要长达1小时。

我们能否使用Open Office打开单个Excel中的每个工作表(标签),并更快地将它们转换为CSV?如果是,请问在Ruby中如何实现?

或者还有更好的解决方案吗?

下面是一个使用Roo gem的小例子:

xls = Roo::Excel.new(source_excel_file)
xls.each_with_pagename do |name, sheet|
  # p sheet.to_csv(File.join(dest_csv_dir,name + ".csv"))
  #sheet.parse(:clean => true)#.to_csv(File.join(dest_csv_dir,name + ".csv"))
  puts name
  puts sheet.parse(:clean => true)
end

http://www.railshorde.com/blog/ruby-convert-excel-file-to-csv - Animesh
4个回答

5

勇敢的前言:我对 Ruby 和 Rails 几乎一无所知,但我之前曾经使用过 Excel。我在本地计算机上创建了一个虚假的工作簿,其中包含 5 个工作表,每个工作表都有 10 列和 1000 行随机生成的数字。我使用以下方法将每个工作表转换为其自己的 CSV 文件:

require 'win32ole'
require 'csv'

# configure a workbook, turn off excel alarms
xl = WIN32OLE.new('excel.application')
book = xl.workbooks.open('C:\stack\my_workbook.xlsx')
xl.displayalerts = false

# loop through all worksheets in the excel file
book.worksheets.each do |sheet|
  last_row = sheet.cells.find(what: '*', searchorder: 1, searchdirection: 2).row
  last_col = sheet.cells.find(what: '*', searchorder: 2, searchdirection: 2).column
  export = File.new('C:\\stack\\' + sheet.name + '.csv', 'w+')
  csv_row = []

  # loop through each column in each row and write to CSV
  (1..last_row).each do |xlrow|
    (1..last_col).each do |xlcol|
      csv_row << sheet.cells(xlrow, xlcol).value
    end
    export << CSV.generate_line(csv_row)
    csv_row = []
  end
end

# clean up
book.close(savechanges: 'false')
xl.displayalerts = true
xl.quit

这个脚本的眼球基准大约为30秒,每次尝试都会在这个时间上下几秒钟。

但我假设它是针对Windows机器的。我想我应该提到它,但我认为它在Mac / Unix / Linux上不起作用,对吗? - Arunachalam
这是一个适用于Windows用户的好解决方案,但不幸的是我从未使用过Windows机器。我使用Mac,并且我的代码在Linux机器上运行。 - Arunachalam
非常愚蠢的问题,但是在*nix上无法获取win32ole吗? - Dan
@DanPantry,很不可能。在底层,win32ole就像“使用已安装的Microsoft Office来完成工作”。当您使用Windows+Office时,它非常方便(此评论中的所有示例都是从Office VBA帮助直接翻译的);但在任何其他环境中,您都无法获得它。 - zverok

2
xls_file = Roo::Excelx.new('test.xlsx')
CSV.open('test.csv') do |csv|
    (2..xls_file.last_row).each do |i| # if you do not need header otherwise (1..xls_file.last_row)
        csv << a.row(i)
    end
end

1
太低了:D。这里还有一个替代方案https://github.com/scpike/excel2csv/blob/master/src/excel2csv.rb但大多数情况下,shanky Munjal所说的是正确的。 - Lucian Tarna

2
我假设我们谈论的是旧版Excel格式(xls),无论如何,似乎spreadsheet gem不能处理xlsx格式。我建议尝试其中一种命令行电子表格转换器:catdoc包中的xls2csv(速度很快,但并非所有Excel文件都能成功处理),或者gnumeric包中的ssconvert(速度适中,需要安装整个GNumeric,这在某些服务器上可能不可选,但非常强大)。注意:解析Excel时,roo只需要电子表格并将其包装在自己的API中,因此它永远不可能比电子表格更快或更可靠。另外,如果我记得正确的话(虽然那是几年前的事了),尝试从Ruby自动化操作OpenOffice既难且慢。

我对xls2csv唯一的问题是,如果我在单个Excel中有多个工作表,并且希望它们成为单独的CSV文件,该怎么办。 - Arunachalam
xls2csv有一个-b选项-"sheet break string"。因此,如果您的xls文件已成功解析为xls2csv(我的没有,所以我无法测试它),则可以使用一些更多的bash魔法(例如这里)拆分输出文件;或者您可以使用popen在Ruby中捕获输出,并仅对其使用常规的split方法。 - zverok
我的也没有被解析 :( 。 - Arunachalam
尝试使用ssconvert,但如果在服务器上,则除了安装完整的gnumeric之外,它没有其他选项(而这又需要所有gnome库)。 - zverok

1

请确保您正在使用最新版本的Roo(1.13.2)。

另外,请确保您正在使用跳过末尾空行补丁:

https://github.com/Empact/roo/blob/master/lib/roo/worksheet.rb

如果您可以发布一个解析时间较长的电子表格,这可能有助于这里的人帮助您。只需确保删除任何机密数据即可。

是的,我正在使用最新的 gem。我尝试了使用 roo gem 的这个例子,但是速度非常慢。 - Arunachalam
xls = Roo::Excel.new(source_excel_file) xls.each_with_pagename do |name, sheet|

p sheet.to_csv(File.join(dest_csv_dir,name + ".csv"))

#sheet.parse(:clean => true)#.to_csv(File.join(dest_csv_dir,name + ".csv")) puts name puts sheet.parse(:clean => true) end
- Arunachalam
你能给我一个使用Roo在单个Excel中处理多个工作表的例子吗? - Arunachalam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接