使用PHP导出CSV和TSV文件

最近一直在使用Excel,没有使用CSV。
以前一直使用fgetcsv来读取,但最近重新尝试使用时,发现使用SplFileObject或者SplTempFileObject会更加方便。
(还可以用于创建普通文件)

CSV(Comma-Separated Values,逗号分隔值)

阅读

headA,headB,headC
dataA,"data,B","data""C"
$read_file_path = __DIR__.'/read.csv';
$file = new \SplFileObject($read_file_path, 'r');
$file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD);// 空行無視はSKIP_EMPTYとREAD_AHEADを共に設定する

foreach ($file as $row)
{
    var_dump($row);
}

dd($file);// Laravelの出力用ヘルパ関数

输出结果

array(3) { [0]=> string(8) "headA" [1]=> string(5) "headB" [2]=> string(5) "headC" }
array(3) { [0]=> string(5) "dataA" [1]=> string(6) "data,B" [2]=> string(6) "data"C" }

SplFileObject {#63632 ▼
  path: "/home/public/app/app/Http/Controllers"
  filename: "read.csv"
  basename: "read.csv"
  pathname: "/home/public/app/app/Http/Controllers/read.csv"
  extension: "csv"
  realPath: "/home/public/app/app/Http/Controllers/read.csv"
  aTime: 2018-02-21 20:15:37
  mTime: 2018-02-21 20:15:37
  cTime: 2018-02-21 20:15:37
  inode: 4407
  size: 48
  perms: 0100777
  owner: 1000
  group: 50
  type: "file"
  writable: true
  readable: true
  executable: true
  file: true
  dir: false
  link: false
  csvControl: array:3 [▶]
  flags: READ_AHEAD|SKIP_EMPTY|READ_CSV
  maxLineLen: 0
  fstat: array:26 [▶]
  eof: false
  key: 0
}

写下

$save_file_path = __DIR__.'/save.csv';
$file = new \SplFileObject($save_file_path, 'w');// ファイルは作成してくれます。

$data = [];
$data[] = ['headA', 'headB', 'headC'];
$data[] = ['dataA', 'data,B', 'data"C'];

foreach ($data as $row) {
    $file->fputcsv($row);
}

dd($file);// Laravelの出力用ヘルパ関数
headA,headB,headC
dataA,"data,B","data""C"

输出结果

SplFileObject {#63653 ▼
  path: "/home/public/app/app/Http/Controllers"
  filename: "save.csv"
  basename: "save.csv"
  pathname: "/home/public/app/app/Http/Controllers/save.csv"
  extension: "csv"
  realPath: "/home/public/app/app/Http/Controllers/save.csv"
  aTime: 2018-02-21 20:47:28
  mTime: 2018-02-21 20:47:28
  cTime: 2018-02-21 20:47:28
  inode: 4422
  size: 44
  perms: 0100777
  owner: 1000
  group: 50
  type: "file"
  writable: true
  readable: true
  executable: true
  file: true
  dir: false
  link: false
  csvControl: array:3 [▶]
  flags: 0
  maxLineLen: 0
  fstat: array:26 [▶]
  eof: false
  key: 0
}

TSV可以用中国本土的方式改写为「通信服务提供商」。

阅读

headA   headB   headC
dataA   "data   B"  "data""C"
$read_file_path = __DIR__.'/read.tsv';
$file = new \SplFileObject($read_file_path, 'r');
$file->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD);// 空行無視はSKIP_EMPTYとREAD_AHEADを共に設定する
$file->setCsvControl("\t");

foreach ($file as $row)
{
    var_dump($row);
}

dd($file);// Laravelの出力用ヘルパ関数

输出结果

array(3) { [0]=> string(5) "headA" [1]=> string(5) "headB" [2]=> string(5) "headC" }
array(3) { [0]=> string(5) "dataA" [1]=> string(6) "data    B" [2]=> string(6) "data"C" }

SplFileObject {#4248 ▼
  path: "/home/public/app/app/Http/Controllers"
  filename: "read.tsv"
  basename: "read.tsv"
  pathname: "/home/public/app/app/Http/Controllers/read.tsv"
  extension: "tsv"
  realPath: "/home/public/app/app/Http/Controllers/read.tsv"
  aTime: 2018-03-01 23:40:18
  mTime: 2018-03-01 23:37:06
  cTime: 2018-03-01 23:37:06
  inode: 751
  size: 43
  perms: 0100777
  owner: 1000
  group: 50
  type: "file"
  writable: true
  readable: true
  executable: true
  file: true
  dir: false
  link: false
  csvControl: array:3 [▶]
  flags: READ_AHEAD|SKIP_EMPTY|READ_CSV
  maxLineLen: 0
  fstat: array:26 [▶]
  eof: true
  key: 2
}

写入

$save_file_path = __DIR__.'/save.tsv';
$file = new \SplFileObject($save_file_path, 'w');// ファイルは作成してくれます。
$file->setCsvControl("\t");

$data = [];
$data[] = ['headA', 'headB', 'headC'];
$data[] = ['dataA', "data\tB", 'data"C'];

foreach ($data as $row) {
    $file->fputcsv($row);
}

dd($file);// Laravelの出力用ヘルパ関数
headA   headB   headC
dataA   "data   B"  "data""C"

输出结果

SplFileObject {#4261 ▼
  path: "/home/public/app/app/Http/Controllers"
  filename: "save.tsv"
  basename: "save.tsv"
  pathname: "/home/public/app/app/Http/Controllers/save.tsv"
  extension: "tsv"
  realPath: "/home/public/app/app/Http/Controllers/save.tsv"
  aTime: 2018-03-01 23:56:42
  mTime: 2018-03-01 23:56:42
  cTime: 2018-03-01 23:56:42
  inode: 869
  size: 43
  perms: 0100777
  owner: 1000
  group: 50
  type: "file"
  writable: true
  readable: true
  executable: true
  file: true
  dir: false
  link: false
  csvControl: array:3 [▶]
  flags: 0
  maxLineLen: 0
  fstat: array:26 [▶]
  eof: false
  key: 0
}

将CSV或TSV格式的字符串转换为数组。只需要在临时文件对象中进行添加并获取即可。

$csvString = 'dataA,"data,B","data""C"';
$tempFile = new \SplTempFileObject();
$tempFile->setFlags(\SplFileObject::READ_CSV | \SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD);
$tempFile->fwrite($csvString);// そのまま書き込む
$tempFile->rewind();// fpを先頭へ 

foreach ($tempFile as $row)
{
    var_dump($row);
}
array(3) {
  [0]=>
  string(5) "dataA"
  [1]=>
  string(6) "data,B"
  [2]=>
  string(6) "data"C"
}

然而,SplTempFileObject是

resultgetPathname()php://tempgetRealPath()false
如果似乎会耗用大量内存的情况,使用/tmp似乎是一个更好的选择。

$testFilePath = tempnam(sys_get_temp_dir(), 'test_');
$testFile = new \SplFileObject($testFilePath, 'w+');
$tempFile->fwrite($csvString);
$tempFile->rewind();

foreach ($tempFile as $row)
{
    var_dump($row);
}

请注意因为文件被占用,所以在使用完后最好用unset($file)等方式进行释放。

请参考SplFileObject::fgetcsv:如何在使用PHP SplFileObject和READ_CSV标志时去除额外的行?

SplFileObject::fputcsv:如何在使用PHP SplFileObject和READ_CSV标志时去除额外的行?

如何在使用PHP SplFileObject和READ_CSV标志时去除多余的行?

SplFileObject::setCsvControl:如何设置PHP SplFileObject的CSV控制参数?

bannerAds