2012-03-30 24 views
8

Tôi có tệp CSV có nhiều cột được sắp xếp. Ví dụ: tôi có thể có các dòng như sau:chia nhỏ tệp văn bản csv dựa trên giá trị cột

19980102,,PLXS,10032,Q,A,,,15.12500,15.00000,15.12500,2 
19980105,,PLXS,10032,Q,A,,,14.93750,14.75000,14.93750,2 
19980106,,PLXS,10032,Q,A,,,14.56250,14.56250,14.87500,2 
20111222,,PCP,63830,N,A,,,164.07001,164.09000,164.12000,1 
20111223,,PCP,63830,N,A,,,164.53000,164.53000,164.55000,1 
20111227,,PCP,63830,N,A,,,165.69000,165.61000,165.64000,1 

Tôi muốn chia tệp dựa trên cột thứ 3, ví dụ: đặt các mục PLXS và PCP vào các tệp riêng của chúng được gọi là PLXS.csv và PCP.csv. Bởi vì tệp xảy ra được sắp xếp trước, tất cả các mục PLXS trước các mục nhập của PCP và vân vân.

Tôi thường làm những việc như thế này trong C++ vì đó là ngôn ngữ tôi biết rõ nhất, nhưng trong trường hợp này, tệp CSV đầu vào của tôi là vài gigabyte và quá lớn để tải vào bộ nhớ trong C++.

Ai đó có thể cho biết cách thực hiện điều này? Perl/Python/php/bash giải pháp là tất cả okay, họ chỉ cần để có thể xử lý các tập tin lớn mà không cần sử dụng bộ nhớ quá mức.

+0

có bạn đã duyệt qua xung quanh ở tất cả? một số câu hỏi liên quan trên trang web này bằng tất cả các ngôn ngữ trên và hơn thế nữa. bạn có thể tìm kiếm: 'site: stackoverflow.com csv chia theo giá trị' hoặc một số biến thể như vậy. best of luck – bernie

Trả lời

1

C++ là tốt nếu bạn biết rõ nhất. Tại sao bạn sẽ thử tải toàn bộ tập tin vào bộ nhớ anyways?

Vì đầu ra phụ thuộc vào cột được đọc, bạn có thể dễ dàng lưu bộ đệm cho tệp đầu ra và ghi vào tệp thích hợp khi bạn xử lý, làm sạch khi bạn đi để giữ chân bộ nhớ tương đối nhỏ.

Tôi làm điều này (mặc dù trong java) khi cần phải thực hiện các chiết xuất lớn từ cơ sở dữ liệu. Các hồ sơ được đẩy vào một dòng đệm tập tin và bất cứ điều gì trong bộ nhớ được làm sạch để dấu chân của chương trình không bao giờ phát triển vượt ra ngoài những gì nó ban đầu bắt đầu tại.

Fly bởi chỗ của quần của tôi pseudo-code:

  1. Tạo một danh sách để tổ chức sản xuất tập tin đệm của bạn
  2. mở suối trong hồ sơ và bắt đầu đọc trong nội dung một dòng tại một thời điểm
  3. Chúng tôi đã gặp phải một bản ghi có luồng tệp mở cho loại nội dung của nó chưa?
    • Có -
      • Lấy dòng tập tin được lưu trữ
      • cửa hàng kỷ lục vào tập tin đó
      • tuôn dòng
    • Không -
      • tạo một dòng suối và lưu nó vào danh sách luồng của chúng tôi
      • lưu bản ghi trên luồng
      • tuôn dòng
  4. Rửa lặp lại ...

Về cơ bản tiếp tục xử lý này cho đến khi chúng tôi vào cuối của tập tin.

Vì chúng tôi không bao giờ lưu nhiều hơn con trỏ vào luồng và chúng tôi đang xóa ngay khi ghi vào luồng, chúng tôi không bao giờ lưu giữ bất kỳ thứ gì trong bộ nhớ của ứng dụng ngoài một bản ghi từ tệp đầu vào. Vì vậy, dấu chân được quản lý.

+2

+1: C++ không phải là vấn đề. Tải toàn bộ tập tin trong bộ nhớ là vấn đề. –

26

Dưới đây là một tuổi học một lót cho bạn (chỉ cần thay thế >> với > để cắt các tập tin đầu ra mỗi lần chạy):

awk -F, '{print >> ($3".csv")}' input.csv 

Do với nhu cầu phổ biến (và một điều tôi vừa gặp), tôi cũng đã viết một phiên bản sẽ sao chép các dòng tiêu đề tới tất cả các tệp:

awk -F, '{fn=$3".csv"} NR==1 {hdr=$0} NR>1&&!($3 in p) {p[$3]; print hdr > fn} NR>1 {print >> fn}' input.csv 

Nhưng bạn chỉ có thể bắt đầu với điều này và kết thúc với awk đầu tiên:

HDR=$(head -1 input.csv); for fn in $(tail -n+2 input.csv | cut -f3 -d, | sort -u); do echo $HDR > $fn.csv; done 

Hầu hết các hệ thống hiện đại có nhị phân awk bao gồm, nhưng nếu bạn không có nó, bạn có thể tìm thấy một exe tại Gawk for Windows

+0

điều này thật tuyệt vời :) nó sẽ tốt hơn nếu chúng ta có thể giữ lại các tiêu đề –

+1

Không có tiêu đề trong bản gốc. Có lẽ bạn có thể đặt một câu hỏi khác? –

0

Nếu ba cột đầu tiên của tập tin của bạn không có dấu phẩy trích dẫn, đơn giản một-liner là:

cat file | perl -e 'while(<>){@a=split(/,/,$_,4);$key=$a[2];open($f{$key},">$key.csv") unless $f{$key};print {$f{$key}} $_;} for $key (keys %f) {close $f{$key}}' 

Nó không tiêu tốn nhiều bộ nhớ (chỉ Asso ciations riêng biệt (3rd_column) -> tập tin xử lý được lưu trữ) và các hàng có thể đến theo thứ tự bất kỳ.

Nếu các cột phức tạp hơn (có chứa dấu phẩy được trích dẫn), sau đó sử dụng Text::CSV.

+0

thực sự, tôi chỉ nhận thấy đây về cơ bản là câu trả lời giống như câu trả lời của Sean Summers bên dưới. –

1
perl -F, -ane '`echo $_ >> $F[2].csv`' < file 

Các tùy chọn dòng lệnh được sử dụng:

  • -n vòng quanh mỗi dòng của tập tin đầu vào
  • -l loại bỏ dòng mới trước khi chế biến, và cho biết thêm họ trở về sau
  • -a autosplit chế độ - chia dòng đầu vào thành mảng @F. Mặc định là chia tách trên khoảng trắng.
  • -e thực thi mã perl
  • -F modifier autosplit, trong trường hợp này chia trên ,

@F là mảng của các từ trong mỗi dòng, lập chỉ mục bắt đầu với $F[0]


Nếu bạn muốn giữ lại tiêu đề, thì cần có một cách tiếp cận phức tạp hơn.

perl splitintofiles.pl file

Nội dung của splitintofiles.pl:

open $fh, '<', $ARGV[0]; 
while ($line = <$fh>) { 
    print $line; 
    if ($. == 1) { 
     $header = $line; 
    } else { 
     # $fields[2] is the 3rd column 
     @fields = split /,/, $line; 
     # save line into hash %c 
     $c{"$fields[2].csv"} .= $line; 
    } 
} 
close $fh; 
for $file (keys %c) { 
    print "$file\n"; 
    open $fh, '>', $file; 
    print $fh $header; 
    print $fh $c{$file}; 
    close $fh; 
} 

đầu vào:

a,b,c,d,e,f,g,h,i,j,k,l 
19980102,,PLXS,10032,Q,A,,,15.12500,15.00000,15.12500,2 
19980105,,PLXS,10032,Q,A,,,14.93750,14.75000,14.93750,2 
19980106,,PLXS,10032,Q,A,,,14.56250,14.56250,14.87500,2 
20111222,,PCP,63830,N,A,,,164.07001,164.09000,164.12000,1 
20111223,,PCP,63830,N,A,,,164.53000,164.53000,164.55000,1 
20111227,,PCP,63830,N,A,,,165.69000,165.61000,165.64000,1 

đầu ra PCP.csv

a,b,c,d,e,f,g,h,i,j,k,l 
20111222,,PCP,63830,N,A,,,164.07001,164.09000,164.12000,1 
20111223,,PCP,63830,N,A,,,164.53000,164.53000,164.55000,1 
20111227,,PCP,63830,N,A,,,165.69000,165.61000,165.64000,1 

đầu ra PLXS.csv

a,b,c,d,e,f,g,h,i,j,k,l 
19980102,,PLXS,10032,Q,A,,,15.12500,15.00000,15.12500,2 
19980105,,PLXS,10032,Q,A,,,14.93750,14.75000,14.93750,2 
19980106,,PLXS,10032,Q,A,,,14.56250,14.56250,14.87500,2 
Các vấn đề liên quan