2010-11-02 111 views
21

我在PHP中使用fputcsv輸出數據庫查詢的逗號分隔文件。當在Ubuntu的gedit中打開文件時,它看起來是正確的 - 每個記錄都有一個換行符(沒有可見的換行符,但可以告訴每個記錄是分開的,在OpenOffice電子表格中打開它可以正確查看文件。)fputcsv和換行符

然而,我們在發送這些文件在客戶端上的Windows,並在他們的系統中,文件進來作爲一個大的,長的線。在Excel中打開它,它根本不識別多行。

我已經閱讀了幾個相似的問題,其中包括this one,其中包含一個鏈接,提供了一個真正的信息性的解釋Great Newline Schism

不幸的是,我們不能只是告訴我們的客戶在一個「智能」編輯器打開該文件。他們需要能夠在Excel中打開它們。是否有任何編程方式來確保添加正確的換行符,以便可以在任何操作系統的電子表格程序中打開文件?

我已經使用了自定義的功能,迫使所有值的報價,因爲fputcsv是選擇它。我試着做這樣的事情:

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

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

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

} 

但是當文件在Windows的文本編輯器打開時,它仍然顯示爲一個單一的長行。

+0

+ 1用於突出顯示我一直在使用 – 2010-11-02 23:30:25

+0

的問題是否包含您的csv字段標題? – ajreal 2010-11-16 19:02:49

+0

在比較上面的代碼和接受的解決方案(假設這個文件是在Linux上生成的)時,它看起來像原來的問題可能是將文件傳輸到客戶端,而不一定是它的生成。例如,通過ASCII模式下的FTP(從Linux到Windows)下載原始文件(使用CR + LF EOL)會導致行結束被破壞。 – MrWhite 2013-10-24 23:32:24

回答

-2

我終於在專家交流中得到了答案;這是什麼工作:

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

將被用來代替標準fputcsv。

+3

我知道這是一個古老的答案,但如果我沒有提到這是來自專家交換的可怕回答,我會失職。它甚至不處理雙引號逃脫。請改用流過濾器。這就是他們在那裏的原因。 http://www.php.net/manual/en/function.stream-filter-register.php – webbiedave 2011-08-01 19:45:52

0

窗口需要\r\n作爲linebreak/carriage返回組合以顯示單獨的行。

+0

是的,我意識到這一點,如果你看看我發佈的代碼,你會看到我正在將\ r \ n添加到正在寫入文件的行中。這似乎並不重要--Windows並不是那樣讀的。 – EmmyS 2010-11-02 18:19:33

2

或者,也可以在本地UNIX格式(\ n只),然後運行生成的文件unix2dos轉換爲\ r \ n個合適的地方輸出。請注意,您的數據不包含\ n's。另外,我看到你正在使用〜的默認分隔符。嘗試\ t的默認分隔符。

+0

unix2dos是否可以安裝在服務器上並以編程方式調用?因爲我實際上必須手動與這些文件聯繫 - 它們以編程方式創建並以編程方式通過電子郵件發送給客戶端。 – EmmyS 2010-11-02 18:18:41

+0

在php中,您可以通過語言調用程序: – Zak 2010-11-02 21:25:40

+1

system('unix2dos myfile.csv') – Zak 2010-11-02 21:26:26

1

我一直在處理類似的情況。這裏有一個解決方案,我發現輸出CSV文件與Windows友好的線結束。

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

我不能,因爲我想流的文件給客戶使用,不能使用fseeks。

+0

謝謝!我會給你一個機會,看看它是否有幫助。 – EmmyS 2010-11-10 17:43:45

5

使用PHP函數fputcsv只寫\ n和不能進行自定義。這使得該功能對微軟環境毫無價值,儘管一些軟件包也會檢測到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); 
+0

感謝您分享這家店鋪! – jjwdesign 2011-11-02 22:12:47

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

輝煌!總之比其他任何解決方案都好,比較好 – max4ever 2012-02-01 16:47:27

+1

很好的答案!我在下面發佈了一個改進版本,保留了使用自定義分隔符和附件並返回fputcsv的原始輸出的可能性 – lucaferrario 2014-01-23 01:04:02

16

這是@約翰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; 
} 
1

由於webbiedave尖out(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); 
...