2010-11-02 43 views
21

Estoy usando fputcsv en PHP para generar un archivo delimitado por comas de una consulta de base de datos. Al abrir el archivo en gedit en Ubuntu, parece correcto: cada registro tiene un salto de línea (sin caracteres de salto de línea visibles, pero se puede decir que cada registro está separado, y abrirlo en la hoja de cálculo de OpenOffice me permite ver el archivo correctamente).códigos fputcsv y newline

Sin embargo, estamos enviando estos archivos a un cliente en Windows, y en sus sistemas, el archivo viene como una línea grande y larga. Al abrirlo en Excel, no reconoce varias líneas en absoluto.

He leído varias preguntas aquí que son bastante similares, incluyendo this one, que incluye un enlace a la explicación realmente informativa Great Newline Schism.

Desafortunadamente, no podemos simplemente decirle a nuestros clientes que abran los archivos en un editor "más inteligente". Deben poder abrirlos en Excel. ¿Existe alguna forma programática para garantizar que se agreguen los caracteres correctos de la línea nueva para que el archivo pueda abrirse en un programa de hoja de cálculo en cualquier sistema operativo?

Ya estoy usando una función personalizada para forzar las comillas alrededor de todos los valores, ya que fputcsv es selectivo al respecto. He intentado hacer algo como esto:

function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){ 

     $glue = $enclosure . $delimiter . $enclosure; 

    return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure."\r\n"); 

} 

Pero cuando se abre el archivo en un editor de texto de Windows, todavía aparece como una sola línea larga.

+0

+ 1 para resaltar un problema que he estado teniendo –

+0

¿incluye su encabezado de campo csv? – ajreal

+0

Al comparar el código anterior con la solución aceptada (suponiendo que este archivo se genere en Linux), parece que el problema original podría haber estado en _transferring_ el archivo al cliente, no necesariamente en su generación. Por ejemplo, la descarga del archivo original (con CR + LF EOL) a través de FTP en modo ASCII, desde Linux a Windows, hubiera resultado en daños en las terminaciones de línea. – MrWhite

Respuesta

-2

Eventualmente recibí una respuesta en intercambio de expertos; esto es lo que funcionó:

function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){ 
    $glue = $enclosure . $delimiter . $enclosure; 
    return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure.PHP_EOL); 
} 

para ser utilizado en lugar de la norma fputcsv.

+3

Sé que esta es una respuesta antigua, pero sería negligente si no mencionara que esta es una respuesta horrible de intercambio de expertos. Ni siquiera maneja escapes de comillas dobles. Por favor, use un filtro de flujo, en su lugar. Es por eso que están ahí. http://www.php.net/manual/en/function.stream-filter-register.php – webbiedave

0

windows necesita \r\n como linebreak/carriage combo de retorno para mostrar líneas separadas.

+0

Sí, soy consciente de eso, y si miras el código que publiqué, verás que adjunto \ r \ n a la línea que estoy escribiendo en el archivo. No parece importar: Windows no lo está leyendo de esa manera. – EmmyS

2

alternativamente, puede generar resultados en formato nativo de Unix (solo \ n) y luego ejecutar unix2dos en el archivo resultante para convertirlo a \ r \ n en los lugares apropiados. Solo tenga cuidado de que sus datos no contengan \ n's. Además, veo que estás usando un separador predeterminado de ~. intente con un separador predeterminado de \ t.

+0

¿Es unix2dos algo que se puede instalar en un servidor y llamar mediante programación? Debido a que, literalmente, tengo contacto manual con estos archivos, se crean programáticamente y se envían por correo electrónico al cliente. – EmmyS

+0

en php, puede hacer llamadas a programas desde el idioma: – Zak

+1

sistema ('unix2dos myfile.csv') – Zak

1

He estado lidiando con una situación similar. Aquí hay una solución que he encontrado que genera archivos CSV con terminaciones de línea amigables para Windows.

http://www.php.net/manual/en/function.fputcsv.php#90883

yo no era capaz de utilizar el ya que estoy tratando de transmitir un archivo para el cliente y no puede utilizar el fseeks.

+0

Gracias! Daré una oportunidad y veré si ayuda. – EmmyS

5

Utilizando la función php, fputcsv solo escribe \ n y no se puede personalizar. Esto hace que la función no tenga valor para el entorno de Microsoft, aunque algunos paquetes también detectarán la línea nueva de Linux.

Todavía los beneficios de fputcsv me mantuvieron buscando una solución para reemplazar el carácter de nueva línea justo antes de enviarlo al archivo. Esto se puede hacer mediante la transmisión de fputcsv a la compilación en php temp stream primero. Luego, adapte los caracteres de nueva línea a lo que desee y luego guárdelos en el archivo.De esta manera:

function getcsvline($list, $seperator, $enclosure, $newline = ""){ 
    $fp = fopen('php://temp', 'r+'); 

    fputcsv($fp, $list, $seperator, $enclosure); 
    rewind($fp); 

    $line = fgets($fp); 
    if($newline and $newline != "\n") { 
     if($line[strlen($line)-2] != "\r" and $line[strlen($line)-1] == "\n") { 
     $line = substr_replace($line,"",-1) . $newline; 
     } else { 
     // return the line as is (literal string) 
     //die('original csv line is already \r\n style'); 
     } 
    } 

     return $line; 
} 

/* to call the function with the array $row and save to file with filehandle $fp */ 
$line = getcsvline($row, ",", "\"", "\r\n"); 
fwrite($fp, $line); 
+0

¡Gracias por compartir este shopimport! – jjwdesign

29
// Writes an array to an open CSV file with a custom end of line. 
// 
// $fp: a seekable file pointer. Most file pointers are seekable, 
// but some are not. example: fopen('php://output', 'w') is not seekable. 
// $eol: probably one of "\r\n", "\n", or for super old macs: "\r" 
function fputcsv_eol($fp, $array, $eol) { 
    fputcsv($fp, $array); 
    if("\n" != $eol && 0 === fseek($fp, -1, SEEK_CUR)) { 
    fwrite($fp, $eol); 
    } 
} 
+1

¡genial! corto y mejor que cualquier otra solución alrededor de – max4ever

+1

¡Gran respuesta! Publiqué una versión mejorada a continuación, conservando la posibilidad de utilizar delimitadores y gabinetes personalizados y devolviendo la salida original de fputcsv – lucaferrario

16

Ésta es una versión mejorada de la gran respuesta de @ John Douthat, conservando la posibilidad de utilizar delimitadores y recintos personalizados y devolver la salida original del fputcsv:

function fputcsv_eol($handle, $array, $delimiter = ',', $enclosure = '"', $eol = "\n") { 
    $return = fputcsv($handle, $array, $delimiter, $enclosure); 
    if($return !== FALSE && "\n" != $eol && 0 === fseek($handle, -1, SEEK_CUR)) { 
     fwrite($handle, $eol); 
    } 
    return $return; 
} 
1

Como webbiedave puntas out (thx!) probablemente la forma más limpia es usar un filtro de flujo.

Es un poco más complejo que otras soluciones, pero funciona incluso en corrientes que no son editables después de escribir a ellos (como una descarga usando $handle = fopen('php://output', 'w');)

Aquí es mi enfoque:

class StreamFilterNewlines extends php_user_filter { 
    function filter($in, $out, &$consumed, $closing) { 

     while ($bucket = stream_bucket_make_writeable($in)) { 
      $bucket->data = preg_replace('/([^\r])\n/', "$1\r\n", $bucket->data); 
      $consumed += $bucket->datalen; 
      stream_bucket_append($out, $bucket); 
     } 
     return PSFS_PASS_ON; 
    } 
} 

stream_filter_register("newlines", "StreamFilterNewlines"); 
stream_filter_append($handle, "newlines"); 

fputcsv($handle, $list, $seperator, $enclosure); 
...