2011-01-11 66 views
14

Tôi có một biểu mẫu (Rails) cho phép tôi tải tệp .csv bằng cách sử dụng file_field. Trong giao diện:Đếm độ dài (số dòng) của tệp CSV?

<% form_for(:upcsv, :html => {:multipart => true}) do |f| %> 
    <table> 
     <tr> 
      <td><%= f.label("File:") %></td> 
      <td><%= f.file_field(:filename) %></td> 
     </tr> 
    </table> 
     <%= f.submit("Submit") %> 
    <% end %> 

Nhấp Gửi chuyển hướng tôi đến một trang khác (create.html.erb). Các tập tin đã được tải tốt, và tôi đã có thể đọc nội dung tốt trong trang thứ hai này. Tôi đang cố gắng hiển thị số dòng trong tệp .csv trong trang thứ hai này.

điều khiển của tôi (semi-giả):

class UpcsvController < ApplicationController 
    def index 
    end 

    def create 
     file = params[:upcsv][:filename] 
     ... 
     #params[:upcsv][:file_length] = file.length # Show number of lines in the file 
     #params[:upcsv][:file_length] = file.size 
     ... 
    end 
end 

Cả file.lengthfile.size lợi nhuận '91' khi tập tin của tôi chỉ chứa 7 dòng. Từ tài liệu Rails mà tôi đọc, khi nút Gửi được nhấp, Rails tạo tệp tạm thời của tệp được tải lên và params[:upcsv][:filename] chứa nội dung của tệp tạm thời/đã tải lên chứ không phải đường dẫn vào tệp. Và tôi không biết cách trích xuất số dòng trong tệp gốc của mình. Cách chính xác để có được số dòng trong tệp là gì?

create.html.erb của tôi:

<table> 
    <tr> 
     <td>File length:</td> 
     <td><%= params[:upcsv][:file_length] %></td> 
    </tr> 
</table> 

Tôi thực sự mới tại Rails (chỉ mới bắt đầu vào tuần trước), vì vậy xin vui lòng chịu với những câu hỏi ngu ngốc của tôi.

Cảm ơn bạn!

Cập nhật: dường như số '91' là số ký tự riêng lẻ (bao gồm cả dấu xuống dòng) trong tệp của tôi. Mỗi dòng trong tệp của tôi có 12 chữ số + 1 dòng mới = 13. 91/13 = 7.

+0

Hãy thực cẩn thận cho phép một tập tin được tải lên mà không cần một số xét nghiệm trên filesize. Hãy tưởng tượng các vấn đề nếu tập tin sử dụng tất cả các không gian đĩa trên ổ đĩa của bạn. Hoặc, nếu tập tin là nhiều gigabyte của vận chuyển-trả về, và mã của bạn trong Rails đang quay cố gắng để đọc và đếm các dòng, DOSing máy chủ của bạn. Nếu bạn đang sử dụng Linux, bạn có thể muốn lệnh 'wc' của hệ điều hành thực hiện việc nâng cấp cho bạn vì nó có thể trả về số lượng dòng và số ký tự trong tệp rất nhanh, mà không có Rails phải mở và đọc nó. –

Trả lời

12

một cách khác để đọc số dòng được

file.readlines.size 
+0

Hey, điều đó thực sự hiệu quả!Tuy nhiên, Rails đã xóa Tempfile sau khi tôi chạy dòng đó nên tôi không thể xử lý nội dung của tệp ... hành vi lạ. Cảm ơn bạn! – Mathias

+0

Bạn được hoan nghênh! – gicappa

+1

@Mathias, bạn có chắc chắn rằng Tempfile bị xóa không? Tôi nghi ngờ bạn chỉ cần tua lại ('file.seek (0)') – cam

16

.length và .size thực sự là từ đồng nghĩa. để có được rowcount của tệp csv, bạn phải phân tích cú pháp nó. chỉ cần đếm các dòng mới trong tệp sẽ không hoạt động, bởi vì các trường chuỗi trong một csv thực sự có thể có dấu ngắt dòng.một cách đơn giản để có được những linecount sẽ là:

CSV.read(params[:upcsv][:filename]).length 
+0

Cảm ơn các bạn! Than ôi, bây giờ tôi nhận được "không thể chuyển đổi Tempfile thành chuỗi". Đây là tham số Yêu cầu: {"commit" => "Gửi", "authenticity_token" => "<-removed->", "upcsv" => {"tên tệp" => # }} Có cách nào để tôi có thể đánh giá tệp .csv thực tế thay vì tệp Tempfile này không? – Mathias

0

Chỉ cần để chứng minh những gì IO # readlines làm:

nếu bạn đã có một nộp như thế này: "asdflkjasdlkfjsdakf \ n asdfjljdaslkdfjlsadjfasdflkj \ n asldfjksdjfa \ n"

trong ray bạn muốn làm, nói:

file = File.open(File.join(Rails.root, 'lib', 'file.json')) 
lines_ary = IO.readlines(file) 
lines_ary.count #=> 3 

IO # readlines chuyển đổi một tập tin vào một mảng các chuỗi bằng cách sử dụng \ n (dòng mới) như dải phân cách, giống như dấu phẩy như vậy thường làm, vì vậy nó là cơ bản giống như

str.split(/\n/) 

Trong thực tế, nếu bạn đã làm

x = file.read 

này

x.split(/\n/) 

sẽ thực hiện tương tự như tệp.readlines

** Đường dây IO # có thể thực sự tiện dụng khi xử lý các tệp có cấu trúc đường lặp ("child_id", "parent_ary", "child_id", "parent_ary ", ...) etc

+0

** để thực hiện các bước trên trong đường ray, một cái gì đó như thế này ("config.autoload_paths + = Dir [" # {config.root}/lib/**/"]") phải được thêm vào config/application.rb –

16

Tất cả các giải pháp được liệt kê ở đây thực sự tải toàn bộ tệp vào bộ nhớ để nhận được số dòng. Nếu bạn đang ở trên một hệ thống Unix-based nhanh hơn nhiều, giải pháp dễ dàng hơn và bộ nhớ hiệu quả là:

`wc -l #{your_file_path}`.to_i 
+0

A hàng trong một CSV có thể chứa các dòng mới, bạn cần phải phân tích cú pháp nó. –

0

Nếu tập tin csv của bạn không phù hợp với bộ nhớ (không thể sử dụng readlines), bạn có thể làm :

def self.line_count(f) 
    i = 0 
    CSV.foreach(f) {|_| i += 1} 
    i 
end 

Không giống như wc -l số này đếm số lượng thực tế, không phải số dòng. Đây có thể khác nếu có các dòng mới trong giá trị trường.

+0

Đó là một ý tưởng hay, nhưng các dòng đọc sẽ trả về một điều tra viên, vì vậy nó không nên đọc toàn bộ nội dung trong bộ nhớ. –

3
CSV.foreach(file_path, headers: true).count 

Trên sẽ exclue tiêu đề trong khi đếm hàng

CSV.read(file_path).count 
+0

'CSV.read (tệp_path, tiêu đề: true) .count' cũng phải trả về số không bao gồm tiêu đề – chetang

Các vấn đề liên quan