1

我正在尝试确定要转储到 MySQL 表中的包含 300 多个字段的大型 CSV 文件 (~5GB) 的最大字段大小。我为该文件提供的 CSV 文件架构提供了不正确的最大字段长度,因此我在导入表时遇到错误。我在 Windows 上运行 Ruby 2.0。

我正在使用一个数组来根据字段的索引(或列)位置存储最大字段长度,即忽略标题中的字段实际名称。我尝试过更高级的东西,比如使用哈希、注入和 zip 等,但似乎一个简单的数组在这里工作得最快。

 field_lengths[0] = Max length of first field   
 field_lengths[1] = Max length of second field
 etc.

该文件太大而无法一次 slurp 或使用 CSV 逐列解析。因此,我打开 CSV 文件并使用 CSV#foreach 解析每一行(使用 :headers => true 选项忽略标题)。对于每一行,我遍历解析的字段值数组,并将字段的长度与存储在 field_length 数组中的当前最大长度进行比较。我意识到有更简单的方法可以使用较小的文件来做到这一点。此方法适用于较大的文件,但我仍然无法使用此方法使其到达特定文件的末尾。

为了避免无法完成文件,我目前定义了许多要读取的行,包括标题 (=n),并在我到达第 n 行时中断。在下面的示例中,我从 CSV 文件中读取了 101 行。(1 个标题行 + 100 个实际数据行)。我不确定文件中有多少行,因为该过程尚未完成。

 require 'csv'
 require 'pp'

 data_file = 'big_file.csv'

 # We're only reading the first 101 lines in this example
 n = 101
 field_lengths = []

 File.open(data_file) do |f|
   CSV.foreach(f, :headers => true, :header_converters => :symbol) do |csv_row|
       break if $. > n
       csv_row.fields.each_with_index do |a,i|
           field_lengths[i] ||= a.to_s.length
           field_lengths[i] = a.to_s.length if field_lengths[i] < a.to_s.length
       end
   end
 end

 pp field_lengths

IO#read 可以读取一定数量的字节,但如果我按字节解析文件,记录可能会被拆分。有没有人有其他建议来解析 CSV 文件,将其拆分为较小的文件?O'Reilly 的 Ruby Cookbook(Lucas Carlson 和 Leonard Richardson,2006 年,第 1 版)建议将大文件分成块(如下所示),但我不确定如何将其扩展到此示例,特别是处理换行符等等

 class File 
    def each_chunk(chunk_size = 1024)
        yield read(chunk_size) until eof?
    end
 end

 open("bigfile.txt") do |f|
    f.each_chunk(15) {|chunk| puts chunk}
 end
4

2 回答 2

2

您使用 CSV.foreach 错误,它需要一个字符串作为文件名:

field_lengths = {}

CSV.foreach(data_file, :headers => true, :header_converters => :symbol) do |csv_row|
  csv_row.each do |k, v|
    field_lengths[k] = [field_lengths[k] || 0, v.length].max
  end
end

pp field_lengths
于 2013-07-23T12:21:45.507 回答
0

给定名为 csv 的变量中的 CSV::Table,您可以将其更改为“按列”并使用收集或映射...或注入。有很多办法。

例如

csv.by_col!
field_lengths = cols.map{|col| col.map{|r| r.is_a?(String) ? r.to_s.length : r.map{|v| v.to_s.length}.max }.max}
  • 第一个映射遍历列。
  • 第二个映射遍历标题(字符串),然后是行值数组。
  • 因此,第三个映射遍历可以将值转换为字符串并返回其长度的行。
  • 第一个最大值是最大值字符串长度。
  • 第二个最大值是标头长度和最大值长度之间的最大值。
  • 最后,您可能希望将 csv 返回到col_or_row

例如

csv.by_col_or_row!
于 2018-01-05T20:46:53.590 回答