Подтвердить что ты не робот

Fputcsv и коды новой строки

Я использую 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, он все равно отображается как одна длинная строка.

4b9b3361

Ответ 1

В конце концов я получил ответ на обмене экспертами; вот что сработало:

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

вместо стандартного fputcsv.

Ответ 2

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

Ответ 3

Это улучшенная версия @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;
}

Ответ 4

Использование 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);

Ответ 5

в качестве альтернативы вы можете выводить в собственном унифицированном формате (только\n), а затем запускать unix2dos в результирующем файле для преобразования в \r\n в соответствующих местах. Просто будьте осторожны, чтобы ваши данные не содержали \n. Кроме того, я вижу, что вы используете разделитель по умолчанию ~. попробуйте разделитель по умолчанию из\t.

Ответ 6

Я имел дело с подобной ситуацией. Вот решение, которое я нашел, выводит CSV файлы с дружественными окнами окончаниями.

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

Мне не удалось использовать, так как я пытаюсь передать файл клиенту и не могу использовать fseeks.

Ответ 7

Как webbiedave указал (спасибо!), возможно, самый чистый способ - использовать фильтр потока.

Это немного сложнее, чем другие решения, но даже работает с потоками, которые не редактируются после их написания (например, с помощью $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);
...

Ответ 8

Windows нуждается в \r\n в качестве linebreak/каретки, чтобы показать отдельные строки.