2017-02-18 82 views
3

我一直在从csv读取数据,如果有大的csv文件,为了避免这种超时(机架12秒超时),我已经从csv读取了25行之后的25行它会返回并再次发出请求,以便继续读取所有行。使用foreach函数从csv文件读取数据

def read_csv(offset) 
    r_count = 1 
    CSV.foreach(file.tempfile, options) do |row| 
    if r_count > offset.to_i 
    #process 
    end 
    r_count += 1 
end 

但这里正在创造一个新的问题,让说,先读,然后25行,当一个请求出现偏移量是25到时候它将读取高达第25行,然后它会开始从26读取并做处理,那么我怎样才能跳过已经阅读过的这些行?,我试过这个如果下一个跳过迭代但失败了,或者有没有其他有效的方法来做到这一点?

+1

正如我的上传功能为我的应用程序 – django

+1

您是否考虑在后台作业中处理CVS? – spickermann

+1

不,因为我必须显示上传到用户的最终数量,如果有任何与csv有关的问题,我也必须告诉用户 – django

回答

0

代码

def read_csv(fileName) 
    lines = (`wc -l #{fileName}`).to_i + 1 
    lines_processed = 0 
    open(fileName) do |csv| 
    csv.each_line do |line| 
     #process 
     lines_processed += 1 
    end 
    end 
end 

纯Ruby - 慢

def read_csv(fileName) 
    lines = open("sample.csv").count 
    lines_processed = 0 
    open(fileName) do |csv| 
    csv.each_line do |line| 
     #process 
     lines_processed += 1 
    end 
    end 
end 

基准

我跑了一个新的基准进行比较提供原始的方法和我自己。我还包括测试文件信息。

"File Information" 
Lines: 1172319 
Size: 126M 

"django's original method" 
Time: 18.58 secs 
Memory: 0.45 MB 

"OneNeptune's method" 
Time: 0.58 secs 
Memory: 2.18 MB 

"Pure Ruby method" 
Time: 0.96 
Memory: 2.06 MB 

说明

注:我添加了一个纯Ruby方法,因为使用wc是有点欺骗,不便于携带。在大多数情况下,使用纯语言解决方案非常重要。

您可以使用此方法处理非常大的CSV文件。

〜2MB内存考虑到文件大小,我觉得它是非常优化的,这会增加内存使用量,但节省的时间似乎是公平交易,并且可以防止超时。

我没有修改方法来取一个文件名,但这只是因为我测试了很多不同的CSV文件,以确保它们都正常工作。如果你愿意,你可以删除它,但它可能会有帮助。

我也删除了偏移量的概念,因为您声明最初包含它以尝试优化自己的解析,但这不再必要。

此外,我还会跟踪文件中有多少行,以及您需要使用该信息后处理了多少行。请注意,这些行仅适用于基于unix的系统,这是避免将整个文件加载到内存中的技巧,它计算新行,并且我将1加到最后一行。如果您不打算将标题计为行,则可以删除+1并将行更改为“行”以更准确。

您可能遇到的另一个后勤问题是需要计算如果CSV文件具有标题时如何处理。

+0

我会试试这个,回复你,谢谢 – django

-2

你可以使用懒读来加速,整个文件不会被读取,只是从文件的开头直到你使用的块。例如 参见http://engineering.continuity.net/csv-tricks/https://reinteractive.com/posts/154-improving-csv-processing-code-with-laziness

您也可以使用SmarterCSV来处理这样的块。

SmarterCSV.process(file_path, {:chunk_size => 1000}) do |chunk| 
    chunk.each do |row| 
    # Do your processing 
    end 
    do_something_else 
end 
enter code here 

我这样做的方式是由结果流给用户,如果你看到正在发生的事情它不打扰那么多,你必须等待。你提到的超时在这里不会发生。 我不是一个Rails用户,所以我举例来自Sinatra,这也可以通过Rails来完成。例如参见http://api.rubyonrails.org/classes/ActionController/Streaming.html

require 'sinatra' 

get '/' do 
    line = 0 
    stream :keep_open do |out| 
    1.upto(100) do |line| # this would be your CSV file opened 
     out << "processing line #{line}<br>" 
     # process line 
     sleep 1 # for simulating the delay 
    end 
    end 
end 

一个仍然较好,但有些复杂的解决方案是使用WebSockets,浏览器会从服务器接收的结果,一旦处理完成。您还需要在客户端使用一些JavaScript来处理此问题。请参阅https://github.com/websocket-rails/websocket-rails