Pregunta

Estoy usando fputcsv en PHP para dar salida a un archivo delimitado por comas de una consulta de base de datos. Al abrir el archivo en gedit en Ubuntu, parece correcta - cada registro tiene un salto de línea (sin caracteres de salto de línea visibles, pero se puede decir cada registro se separa, y abriéndolo en OpenOffice hoja de cálculo me permite ver el archivo correctamente.)

Sin embargo, estamos enviando estos archivos en un cliente de Windows y en sus sistemas, el archivo viene en como uno grande, larga línea. Al abrirlo en Excel, que no reconoce múltiples líneas en absoluto.

He leído varias preguntas aquí que son bastante similares, incluyendo éste , que incluye un enlace a la muy informativo Gran Cisma de nueva línea explicación.

Por desgracia, no podemos decir a nuestros clientes para abrir los archivos en un editor de "inteligente". Tienen que ser capaces de abrirlos en Excel. ¿Hay alguna manera programática para asegurar que se añaden los caracteres de nueva línea correctas por lo que el archivo se puede abrir en un programa de hoja de cálculo en cualquier sistema operativo?

Ya estoy usando una función personalizada para forzar comillas alrededor de todos los valores, ya que fputcsv es selectivo 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.

¿Fue útil?

Solución 8

Me hizo finalmente conseguir una respuesta más a expertos de intercambio; 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 fputcsv estándar.

Otros consejos

// 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);
  }
}

Esta 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;
}

Uso de la función de PHP fputcsv escribe solamente \ n y no se puede modificar para requisitos particulares. Esto hace que el valor de la función de entorno de Microsoft aunque algunos paquetes detectarán la nueva línea Linux también.

Todavía los beneficios de fputcsv me mantuvo la excavación en una solución para reemplazar el carácter de nueva línea antes de enviarla al archivo. Esto se puede hacer enviando la fputcsv a la acumulación en la corriente temporal php primero. A continuación, adaptar el carácter de nueva línea (s) de lo que desea y luego guardar 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);

unix2dos alternativamente, a continuación, puede ejecutar una salida en formato UNIX nativo (\ n solamente) en el archivo resultante para convertir a \ r \ n en los lugares apropiados. Sólo tenga cuidado de que sus datos no contiene \ n de. Además, veo que está utilizando un separador predeterminado de ~. probar un separador predeterminado de \ t.

webbiedave señaló (gracias!) Probablemente la manera más limpia es utilizar un filtro de secuencia.

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í está 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);
...

he estado tratando con una situación similar. He aquí una solución que he encontrado que las salidas de los archivos CSV con ventanas de usar el fin de línea.

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 puedo usar los fseeks.

Windows necesita \r\n como el salto de línea / carro combo de retorno con el fin de mostrar líneas separadas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top