Я использую fputcsv в PHP для вывода файла с разделителями-запятыми запроса базы данных. При открытии файла в gedit в Ubuntu он выглядит корректно – каждая запись имеет разрыв строки (нет видимых символов разрыва строки, но вы можете сказать, что каждая запись разделена, и открытие ее в электронной таблице OpenOffice позволяет мне правильно просматривать файл.)
Однако мы отправляем эти файлы клиенту в Windows, и в их системах файл поставляется в виде одной большой длинной строки. Открывая его в Excel, он не распознает несколько строк.
Я прочитал здесь несколько вопросов, которые очень похожи, в том числе и этот , который включает ссылку на действительно информативное объяснение Великой Новой Шрифты .
К сожалению, мы не можем просто сказать нашим клиентам, чтобы они открывали файлы в «умном» редакторе. Они должны иметь возможность открывать их в Excel. Есть ли какой-либо программный способ обеспечения добавления правильных символов новой строки, чтобы файл можно было открыть в программе для работы с электронными таблицами на любой ОС?
Я уже использую настраиваемую функцию для принудительного цитирования всех значений, поскольку fputcsv является выборочным. Я пробовал сделать что-то вроде этого:
function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){ $glue = $enclosure . $delimiter . $enclosure; return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure."\r\n"); }
Но когда файл открывается в текстовом редакторе Windows, он все равно отображается как одна длинная строка.
// 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); } }
Это улучшенная версия замечательного ответа @John Douthat, сохраняющая возможность использования пользовательских разделителей и корпусов и возвращающий исходный выход 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; }
Использование php-функции fputcsv записывает только \ n и не может быть настроено. Это делает функцию бесполезной для среды microsoft, хотя некоторые пакеты также обнаружат новую линию linux.
Тем не менее преимущества fputcsv заставляли меня копаться в решении для замены символа новой строки перед отправкой в файл. Это может быть сделано путем потоковой передачи fputcsv в сборку в потоке php temp. Затем адаптируйте символ (-ы) новой строки так, как вам угодно, а затем сохраните файл. Как это:
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);
в качестве альтернативы вы можете выводить в собственном формате unix (только \ n), а затем запускать unix2dos в результирующем файле для преобразования в \ r \ n в соответствующих местах. Просто будьте осторожны, чтобы ваши данные не содержали \ n. Кроме того, я вижу, что вы используете разделитель по умолчанию ~. попробуйте разделитель по умолчанию из \ t.
Я занимаюсь подобной ситуацией. Вот решение, которое я нашел, выводя CSV-файлы с дружественными окнами.
http://www.php.net/manual/en/function.fputcsv.php#90883
Я не смог использовать, так как я пытаюсь передать файл клиенту и не могу использовать fseeks.
Как указывал webbiedave (thx!), Самым чистым способом является использование фильтра потока.
Это немного сложнее, чем другие решения, но даже работает с потоками, которые не редактируются после их написания (например, при загрузке с использованием $handle = fopen('php://output', 'w');
)
Вот мой подход:
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); ...
Окна требуют \r\n
как комбинированное преобразование строк / кареток , чтобы показать отдельные строки.
В конце концов я получил ответ на обмене экспертами; вот что сработало:
function my_fputcsv($handle, $fieldsarray, $delimiter = "~", $enclosure ='"'){ $glue = $enclosure . $delimiter . $enclosure; return fwrite($handle, $enclosure . implode($glue,$fieldsarray) . $enclosure.PHP_EOL); }
для использования вместо стандартного fputcsv.