将 .csv 文件读入 PHP 数组

7
我有一个 PHP 程序,它可以读取上传到我的网站上的 .csv 文件。
每次上传时,文件中的字段数量都可能不同。
我想要确定 .csv 文件的大小(即字段数),并将其内容存储在一个数组中。
以下是我目前的代码:
//get the csv file 
$file = $_FILES[csv1][tmp_name]; 
$handle = fopen($file,"r"); 

//loop through the csv file and insert into array
$dataline = fgetcsv($handle,1000,",","'");
$fieldnum = count($dataline);

$recordloop = 0;

while ($dataline) 
{ 

    for ($fieldloop=0; $fieldloop <$fieldnum; $fieldloop++)
    {
        //this is the bit that is wrong
        $dataarray[]=array($dataline[$fieldloop]);
    }

    $data = fgetcsv($handle,1000,",","'");
    $recordloop++;
}

如果有30个字段和200条记录,我想让数组的结构为$dataarray[200][30]。如何将数据放入这种结构的数组中?例如.csv文件:
Row 1 will be field headings
Name, Gender, Ethnicity, DOB, etc .... the number of fields is not fixed - it could be from 30 to 40 fields in this row

Rows 2 onwards will be the records
John, M, British, 10/04/49, etc
Simon, M, British, 04/03/65, etc

回答 - 做了我想要的事情。

$file = $_FILES[csv1][tmp_name]; 
$handle = fopen($file,"r"); 

$matrix = array();
while (($row = fgetcsv($handle, 1000, ",")) !== FALSE) 
{
$matrix[] = $row;
}

你能用CSV样本进行编辑吗? - Adrian Cid Almaguer
1
请查看以下链接:https://dev59.com/_GMm5IYBdhLWcg3wO9Hy 或 https://dev59.com/xW445IYBdhLWcg3ws8Zp 或 https://dev59.com/rHE85IYBdhLWcg3wYSZk 或 https://dev59.com/OFHTa4cB1Zd3GeqPOyGQ。随便选一个。 - But those new buttons though..
3个回答

20

您已经在PHP中拥有此类实现:

$csv = array_map('str_getcsv', file('someCSVfile.csv'));

说明:

  • str_getcsv() - 将CSV字符串解析为一个数组。
  • file() - 将整个文件读入一个数组。
  • array_map(Function, Array)- 对数组中的每个元素应用回调函数后返回包含所有元素的数组。

示例输出:

//CSV
NAME,CLASS,ROOM
Sally,2018,312
Belinda,2017,148

//OUTPUT:
Array(
       [0] => Array([0] => NAME,    [1] => CLASS, [2] => ROOM), 
       [1] => Array([0] => Sally,   [1] => 2018,  [2] => 312),
       [2] => Array([0] => Belinda, [1] => 2017,  [2] => 148)
)

关联键

使用基于array_map方法的两个快速函数来解析带有关联键的内容:

方法1:运行两次

function assoc_getcsv($csv_path) {
    $r = array_map('str_getcsv', file($csv_path));
    foreach( $r as $k => $d ) { $r[$k] = array_combine($r[0], $r[$k]); }
    return array_values(array_slice($r,1));
}  

方法2:仅运行一次

function assoc_getcsv($csv_path) {
    $f = array();
    function parse_csv_assoc($str,&$f){ 
        if (empty($f)) { $f = str_getcsv($str); }
        return array_combine($f, str_getcsv($str));         
    }
    return array_values(array_slice(array_map('parse_csv_assoc', file($csv_path), $f),1));
} 

示例输出:

//CSV
NAME,CLASS,ROOM
Sally,2018,312
Belinda,2017,148

//OUTPUT:
Array(
       [0] => Array([NAME] => Sally,   [CLASS] => 2018,  [ROOM] => 312),
       [1] => Array([NAME] => Belinda, [CLASS] => 2017,  [ROOM] => 148)
)

1
这是一个有趣的简短方式来完成工作。只是出于好奇 - 你是否比较过这种方法和使用SplFileObjectIterator的速度? - tftd
不是 -> 我已经使用这个函数一个月了,可以在大约1-2秒内解析11000行的CSV文件。 - Shlomi Hassid
这绝对比使用 SplFileObject 快两倍。这是我的测试 - tftd
@tftd 很棒的测试!你准备好测试另外两种方法了吗? - Shlomi Hassid

4

这个函数将读取一个CSV文件并生成一个多维数组。

function fromCSVFile( $file) {
    // open the CVS file
    $handle = @fopen( $file, "r");
    if ( !$handle ) {
        throw new \Exception( "Couldn't open $file!" );
    }

    $result = [];

    // read the first line
    $first = strtolower( fgets( $handle, 4096 ) );
    // get the keys
    $keys = str_getcsv( $first );

    // read until the end of file
    while ( ($buffer = fgets( $handle, 4096 )) !== false ) {

        // read the next entry
        $array = str_getcsv ( $buffer );
        if ( empty( $array ) ) continue;

        $row = [];
        $i=0;

        // replace numeric indexes with keys for each entry
        foreach ( $keys as $key ) {
            $row[ $key ] = $array[ $i ];
            $i++;
        }

        // add relational array to final result
        $result[] = $row;
    }

    fclose( $handle );
    return $result;
}

如果您的 .CSV 文件看起来像这样:

如下所示:

Name,Gender,Ethnicity,DOB
John,M,British,10/04/49
Simon,M,British,04/03/65

你将会得到这个:
(
    [0] => Array
        (
            [name] => John
            [gender] => M
            [ethnicity] => British
            [dob] => 10/04/49
        )

    [1] => Array
        (
            [name] => Simon
            [gender] => M
            [ethnicity] => British
            [dob] => 04/03/65
        )

)

1
谢谢,这很好,但我实际上不想让第一行成为键。我希望它们仍然保留在数组的第一行。 - RGriffiths

4

1.csv:

Name,Gender,Ethnicity,DOB
John,M,British,10/04/49
Simon,M,British,04/03/65

使用file()函数将csv文件读入数组中,然后通过循环遍历该数组,并使用explode()函数获取所有字段并将其放入数组元素中,创建一个新的$array
<?php

$file = '1.csv';
$content = file($file);

$array = array();

for($i = 1; $i < count($content); $i++) {
    $line = explode(',', $content[$i]);
    for($j = 0; $j < count($line); $j++) {
        $array[$i][$j + 1] = $line[$j];
    }   
}   

print_r($array);

?>

输出:

Array
(
    [1] => Array
        (
            [1] => John
            [2] => M
            [3] => British
            [4] => 10/04/49

        )

    [2] => Array
        (
            [1] => Simon
            [2] => M
            [3] => British
            [4] => 04/03/65

        )

)

如果您想获取 记录:2字段:4,可以这样做:

echo $array[2][4];

输出:

04/03/65

@RichardGriffiths 你有什么进展了吗? - Adrian Cid Almaguer
我已经找到了答案。我已经编辑了问题,展示了答案。感谢你的帮助。 - RGriffiths

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接