2012-03-30 26 views
8

Tengo archivos CSV que tienen varias columnas que se ordenan. Por ejemplo, podría tener líneas de este tipo:dividir archivo de texto grande csv basado en el valor de columna

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 

me gustaría dividir el archivo basado en la tercera columna, por ejemplo, ponga las entradas PLXS y PCP en sus propios archivos llamados PLXS.csv y PCP.csv. Debido a que el archivo pasa a estar previamente ordenado, todas las entradas de PLXS están antes de las entradas de PCP, y así sucesivamente.

Generalmente termino haciendo cosas como esta en C++ ya que ese es el lenguaje que mejor conozco, pero en este caso, mi archivo CSV de entrada es de varios gigabytes y demasiado grande para cargarlo en la memoria en C++.

¿Alguien puede mostrar cómo se puede lograr esto? Las soluciones Perl/Python/php/bash están bien, solo necesitan poder manejar el gran archivo sin un uso excesivo de memoria.

+0

tienen ya había navegado alrededor a todos? varias preguntas relacionadas en este sitio en todos los idiomas anteriores y más. puede buscar: 'sitio: stackoverflow.com csv dividido por valor' o alguna de esas variantes. la mejor de las suertes – bernie

Respuesta

1

C++ está bien si lo conoces mejor. ¿Por qué intentarías cargar todo el archivo en la memoria de todos modos?

Dado que la salida depende de la columna que se está leyendo, puede almacenar fácilmente los almacenamientos intermedios para los archivos de salida y rellenar el registro en el archivo apropiado mientras procesa, limpiando para mantener la huella de memoria relativamente pequeña.

Lo hago (aunque en java) cuando necesito tomar extractos masivos de una base de datos. Los registros se insertan en una secuencia de búfer de archivo y cualquier elemento de la memoria se limpia para que la huella del programa nunca crezca más allá de lo que inicialmente comienza.

mosca por el asiento de mis pantalones pseudo-código:

  1. Crear una lista de celebrar la salida de archivos de memoria intermedia
  2. corriente abierta en el archivo y comenzar a leer en el contenido de una línea a la vez
  3. ¿Encontramos un registro que todavía tiene un flujo de archivos abierto para su tipo de contenido?
    • Sí -
      • Consigue la secuencia de archivo almacenado
      • almacenar el registro en ese archivo
      • ras la corriente
    • n -
      • crear una corriente y guardarlo nuestra lista de corrientes
      • almacenar el registro en el stream
      • ras la corriente
  4. Enjuague repita ...

Básicamente continuar este tratamiento hasta que estemos al final del archivo.

Como nunca almacenamos más que punteros en las transmisiones y nos estamos sonrojando tan pronto como escribimos en las transmisiones, no tenemos nada que permanezca en la memoria de la aplicación más que un registro del archivo de entrada. Por lo tanto, la huella se mantiene manejable.

+2

+1: C++ no es el problema. Cargar todo el archivo en la memoria es el problema. –

26

Aquí es una escuela vieja un trazador de líneas para usted (basta con sustituir el >> con > para truncar los archivos de salida de cada carrera):

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

Debido a la demanda popular (y un picor que acabo de tener), también he escrito una versión que duplicará las líneas de encabezado de todos los archivos:

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 

Pero usted podría comenzar con esto y terminar con el primer awk:

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

mayoría de los sistemas modernos tienen el binario awk incluido, pero si no lo tiene, se puede encontrar en un exe Gawk for Windows

+0

esto es increíble :) sería aún mejor si pudiéramos conservar los encabezados –

+1

No había encabezados en el original. ¿Quizás puedas hacer una pregunta diferente? –

0

Si las tres primeras columnas de su archivo no tienen comas citados, un sencillo de una sola línea es:

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}}' 

no consume mucha memoria (sólo el Asso ciations distinct (3rd_column) -> file-handle se almacenan) y las filas pueden venir en cualquier orden.

Si las columnas son más complejas (contienen comas por ejemplo), utilice Text::CSV. Se utilizan

+0

en realidad, solo noto que esta es esencialmente la misma respuesta que la de Sean Summers a continuación. –

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

Estas opciones de línea de comandos:

  • -n bucle alrededor de cada línea del archivo de entrada
  • -l elimina los saltos de línea antes de la transformación, y los añade de nuevo en después
  • -a autosplit mode - divide las líneas de entrada en la matriz @F. El valor predeterminado es la división en espacios en blanco.
  • -e ejecutar el código Perl
  • -F modificador autosplit, en este caso se divide en ,

@F es la matriz de palabras en cada línea, indexada a partir de $F[0]


Si quiere conservar el encabezado, entonces se requiere un enfoque más complicado.

perl splitintofiles.pl file

Contenido de 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; 
} 

de entrada:

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 

PCP.csv salida

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 

salida 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 
Cuestiones relacionadas