fputcsv 和换行代码

发布于 2024-09-30 11:33:16 字数 929 浏览 2 评论 0原文

我在 PHP 中使用 fputcsv 输出数据库查询的逗号分隔文件。当在 Ubuntu 中的 gedit 中打开文件时,它看起来是正确的 - 每条记录都有一个换行符(没有可见的换行符,但你可以看出每条记录是分开的,在 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 文本编辑器中打开文件时,它仍然显示为一行长线。

I'm using fputcsv in PHP to output a comma-delimited file of a database query. When opening the file in gedit in Ubuntu, it looks correct - each record has a line break (no visible line break characters, but you can tell each record is separated,and opening it in OpenOffice spreadsheet allows me to view the file correctly.)

However, we're sending these files on to a client on Windows, and on their systems, the file comes in as one big, long line. Opening it in Excel, it doesn't recognize multiple lines at all.

I've read several questions on here that are pretty similar, including this one, which includes a link to the really informative Great Newline Schism explanation.

Unfortunately, we can't just tell our clients to open the files in a "smarter" editor. They need to be able to open them in Excel. Is there any programmatic way to ensure that the correct newline characters are added so the file can be opened in a spreadsheet program on any OS?

I'm already using a custom function to force quotes around all values, since fputcsv is selective about it. I've tried doing something like this:

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

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

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

}

But when the file is opened in a Windows text editor, it still shows up as a single long line.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

吃→可爱长大的 2024-10-07 11:33:16
// 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);
  }
}
// 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);
  }
}
野味少女 2024-10-07 11:33:16

这是 @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;
}

This is an improved version of @John Douthat's great answer, preserving the possibility of using custom delimiters and enclosures and returning fputcsv's original output:

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;
}
自由如风 2024-10-07 11:33:16

使用php函数fputcsv只写入\n并且不能自定义。这使得该函数对于 Microsoft 环境毫无价值,尽管某些软件包也会检测 Linux 换行符。

尽管如此,fputcsv 的好处仍然让我深入研究了一种解决方案,以在发送到文件之前替换换行符。这可以通过首先将 fputcsv 流式传输到 php 临时流中的构建来完成。然后将换行符调整为您想要的任何内容,然后保存到文件。像这样:

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

Using the php function fputcsv writes only \n and cannot be customized. This makes the function worthless for microsoft environment although some packages will detect the linux newline also.

Still the benefits of fputcsv kept me digging into a solution to replace the newline character just before sending to the file. This can be done by streaming the fputcsv to the build in php temp stream first. Then adapt the newline character(s) to whatever you want and then save to file. Like this:

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);
微凉 2024-10-07 11:33:16

正如 webbiedave 指出的(谢谢!)可能最干净的方法是使用流过滤器。

它比其他解决方案复杂一点,但甚至适用于写入后不可编辑的流(例如使用 $handle = fopen('php://output', 'w');< 进行下载/code> )

这是我的方法:

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);
...

As webbiedave pointed out (thx!) probably the cleanest way is to use a stream filter.

It is a bit more complex than other solutions, but even works on streams that are not editable after writing to them (like a download using $handle = fopen('php://output', 'w'); )

Here is my approach:

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);
...
奈何桥上唱咆哮 2024-10-07 11:33:16

或者,您可以以本机 unix 格式(仅限 \n)输出,然后在结果文件上运行 unix2dos 以在适当的位置转换为 \r\n。请注意您的数据不包含 \n's 。另外,我发现您正在使用默认分隔符 ~ 。尝试使用默认分隔符 \t 。

alternatively, you can output in native unix format (\n only) then run unix2dos on the resulting file to convert to \r\n in the appropriate places. Just be careful that your data contains no \n's . Also, I see you are using a default separator of ~ . try a default separator of \t .

中二柚 2024-10-07 11:33:16

我一直在处理类似的情况。这是我发现的一个解决方案,可以输出带有 Windows 友好行结尾的 CSV 文件。

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

我无法使用,因为我正在尝试将文件流式传输到客户端并且无法使用 fseeks。

I've been dealing with a similiar situation. Here's a solution I've found that outputs CSV files with windows friendly line-endings.

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

I wasn't able to use the since I'm trying to stream a file to the client and can't use the fseeks.

东风软 2024-10-07 11:33:16

PHP 8.1.0 引入了新的 eol 选项,请参见官方文档

PHP 8.1.0 has introduced a new option for eol, see the official document

动次打次papapa 2024-10-07 11:33:16

Windows 需要 \r\n 作为 linebreak/carriage 返回组合才能显示单独的行。

windows needs \r\n as the linebreak/carriage return combo in order to show separate lines.

简单气质女生网名 2024-10-07 11:33:16

最终我在专家交流中得到了答案;这是有效的:

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

用于代替标准 fputcsv。

I did eventually get an answer over at experts-exchange; here's what worked:

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

to be used in place of standard fputcsv.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文