如何使用 PHP 和 fgetcsv 函数从 CSV 文件创建数组

Posted

技术标签:

【中文标题】如何使用 PHP 和 fgetcsv 函数从 CSV 文件创建数组【英文标题】:How to create an array from a CSV file using PHP and the fgetcsv function 【发布时间】:2010-11-19 03:59:34 【问题描述】:

谁能提供一个代码来使用 fgetcsv 从 CSV 文件创建一个数组?

我使用以下代码从一个简单的 CSV 文件创建了一个数组,但是当我的一个字段有多个逗号(例如地址)时,它就无法正常工作。

$lines =file('CSV Address.csv');

foreach($lines as $data)

list($name[],$address[],$status[])
= explode(',',$data);

*另外,我的托管服务不支持 str_getcsv。

以上代码不适用于以下 CSV 文件示例。第一栏是姓名,第二栏是地址,第三栏是婚姻状况。

Scott L. Aranda,"123 Main Street, Bethesda, Maryland 20816",Single
Todd D. Smith,"987 Elm Street, Alexandria, Virginia 22301",Single
Edward M. Grass,"123 Main Street, Bethesda, Maryland 20816",Married
Aaron G. Frantz,"987 Elm Street, Alexandria, Virginia 22301",Married
Ryan V. Turner,"123 Main Street, Bethesda, Maryland 20816",Single

【问题讨论】:

卡在 php 5.2 上吧?我对你有感觉,我和我的托管服务提供商在同一条船上。 你可以使用这个助手:github.com/rap2hpoutre/csv-to-associative-array 【参考方案1】:

就像你在标题中所说的那样,fgetcsv 是要走的路。它非常易于使用。

$file = fopen('myCSVFile.csv', 'r');
while (($line = fgetcsv($file)) !== FALSE) 
  //$line is an array of the csv elements
  print_r($line);

fclose($file);

如果fopen() 失败,您需要在其中进行更多错误检查,但这可以逐行读取 CSV 文件并将该行解析为数组。

【讨论】:

感谢 Dave,但您的示例仅提供了具有以下三个位置的数组:$line[0]、$line[1] 和 $line[2]。这对第一行来说很好,但我需要为第二行、第三行、第四行等创建单独的位置。这样我就可以分别操纵线条。希望这是有道理的 @Thomas 如果您需要一组姓名、地址和状态,您可以按照上面的操作:list($names[], $addresses[], $statuses[]) = $line; 我有一个关于这个函数的问题,如果其中一个 CSV 字段中有一个新行,它当前会将该行解析为单个记录吗?或者它会返回两个(损坏的)记录吗? 为什么我们需要在最后关闭? @angrykiwi 否则你会不必要地消耗记忆。其他进程无法访问该文件。【参考方案2】:

我认为str_getcsv() 语法更简洁,它也不需要将 CSV 存储在文件系统中。

$csv = str_getcsv(file_get_contents('myCSVFile.csv'));

echo '<pre>';
print_r($csv);
echo '</pre>';

或逐行解决:

$csv = array();
$lines = file('myCSVFile.csv', FILE_IGNORE_NEW_LINES);

foreach ($lines as $key => $value)

    $csv[$key] = str_getcsv($value);


echo '<pre>';
print_r($csv);
echo '</pre>';

或者对于没有 str_getcsv() 的逐行解决方案:

$csv = array();
$file = fopen('myCSVFile.csv', 'r');

while (($result = fgetcsv($file)) !== false)

    $csv[] = $result;


fclose($file);

echo '<pre>';
print_r($csv);
echo '</pre>';

【讨论】:

仅供参考:str_getcsv() 仅从 PHP 5.3.0 开始可用。我正在做的项目错过了 1 个版本的 DOH! (我们使用的是 5.2.9 atm)。 这很好,除非你有内存限制。 fgetcsv 解决方案适用于任何硬件配置。 当心! str_getcsv 存在一个错误,使其忽略行尾:bugs.php.net/bug.php?id=55763&edit=1 注意你可以这样做:while(!feof($file)) $csv[] = fgetcsv($file); 而不是 while (($result = fgetcsv($file)) !== false) $csv[] = $result; 【参考方案3】:

我创建了一个将 csv 字符串转换为数组的函数。该函数知道如何转义特殊字符,并且可以使用或不使用附件字符。

$dataArray = csvstring_to_array( file_get_contents('Address.csv'));

我用你的 csv 样本试了一下,它按预期工作!

function csvstring_to_array($string, $separatorChar = ',', $enclosureChar = '"', $newlineChar = "\n") 
    // @author: Klemen Nagode
    $array = array();
    $size = strlen($string);
    $columnIndex = 0;
    $rowIndex = 0;
    $fieldValue="";
    $isEnclosured = false;
    for($i=0; $i<$size;$i++) 

        $char = $string$i;
        $addChar = "";

        if($isEnclosured) 
            if($char==$enclosureChar) 

                if($i+1<$size && $string$i+1==$enclosureChar)
                    // escaped char
                    $addChar=$char;
                    $i++; // dont check next char
                else
                    $isEnclosured = false;
                
            else 
                $addChar=$char;
            
        else 
            if($char==$enclosureChar) 
                $isEnclosured = true;
            else 

                if($char==$separatorChar) 

                    $array[$rowIndex][$columnIndex] = $fieldValue;
                    $fieldValue="";

                    $columnIndex++;
                elseif($char==$newlineChar) 
                    echo $char;
                    $array[$rowIndex][$columnIndex] = $fieldValue;
                    $fieldValue="";
                    $columnIndex=0;
                    $rowIndex++;
                else 
                    $addChar=$char;
                
            
        
        if($addChar!="")
            $fieldValue.=$addChar;

        
    

    if($fieldValue)  // save last field
        $array[$rowIndex][$columnIndex] = $fieldValue;
    
    return $array;

【讨论】:

【参考方案4】:

老问题,但仍然适用于 PHP 5.2 用户。 str_getcsv 从 PHP 5.3 开始可用。我编写了一个与 fgetcsv 本身配合使用的小函数。

以下是我来自https://gist.github.com/4152628的函数:

function parse_csv_file($csvfile) 
    $csv = Array();
    $rowcount = 0;
    if (($handle = fopen($csvfile, "r")) !== FALSE) 
        $max_line_length = defined('MAX_LINE_LENGTH') ? MAX_LINE_LENGTH : 10000;
        $header = fgetcsv($handle, $max_line_length);
        $header_colcount = count($header);
        while (($row = fgetcsv($handle, $max_line_length)) !== FALSE) 
            $row_colcount = count($row);
            if ($row_colcount == $header_colcount) 
                $entry = array_combine($header, $row);
                $csv[] = $entry;
            
            else 
                error_log("csvreader: Invalid number of columns at line " . ($rowcount + 2) . " (row " . ($rowcount + 1) . "). Expected=$header_colcount Got=$row_colcount");
                return null;
            
            $rowcount++;
        
        //echo "Totally $rowcount rows found\n";
        fclose($handle);
    
    else 
        error_log("csvreader: Could not read CSV \"$csvfile\"");
        return null;
    
    return $csv;

返回

开始阅读 CSV

Array
(
    [0] => Array
        (
            [vid] => 
            [agency] => 
            [division] => Division
            [country] => 
            [station] => Duty Station
            [unit] => Unit / Department
            [grade] => 
            [funding] => Fund Code
            [number] => Country Office Position Number
            [wnumber] => Wings Position Number
            [title] => Position Title
            [tor] => Tor Text
            [tor_file] => 
            [status] => 
            [datetime] => Entry on Wings
            [laction] => 
            [supervisor] => Supervisor Index Number
            [asupervisor] => Alternative Supervisor Index
            [author] => 
            [category] => 
            [parent] => Reporting to Which Position Number
            [vacant] => Status (Vacant / Filled)
            [index] => Index Number
        )

    [1] => Array
        (
            [vid] => 
            [agency] => WFP
            [division] => KEN Kenya, The Republic Of
            [country] => 
            [station] => Nairobi
            [unit] => Human Resources Officer P4
            [grade] => P-4
            [funding] => 5000001
            [number] => 22018154
            [wnumber] => 
            [title] => Human Resources Officer P4
            [tor] => 
            [tor_file] => 
            [status] => 
            [datetime] => 
            [laction] => 
            [supervisor] => 
            [asupervisor] => 
            [author] => 
            [category] => Professional
            [parent] => 
            [vacant] => 
            [index] => xxxxx
        )
) 

【讨论】:

顺便说一句,您可以将可选参数添加到 fgetcsv 以更改分隔符、附件字符等。【参考方案5】:

试试这个代码:

function readCsv($file)

    if (($handle = fopen($file, 'r')) !== FALSE) 
        while (($lineArray = fgetcsv($handle, 4000)) !== FALSE) 
            print_r(lineArray);
        
        fclose($handle);
    

【讨论】:

发布与提问者完全相同的答案的原因是什么?【参考方案6】:
$arrayFromCSV =  array_map('str_getcsv', file('/path/to/file.csv'));

【讨论】:

很简洁,但是返回的是数组,不是矩阵【参考方案7】:

请在下方找到来自@knagode 的函数链接,该链接通过跳过行参数进行了增强。 https://gist.github.com/gabrieljenik/47fc38ae47d99868d5b3#file-csv_to_array

<?php
    /**
     * Convert a CSV string into an array.
     * 
     * @param $string
     * @param $separatorChar
     * @param $enclosureChar
     * @param $newlineChar
     * @param $skip_rows
     * @return array
     */
    public static function csvstring_to_array($string, $skip_rows = 0, $separatorChar = ';', $enclosureChar = '"', $newlineChar = "\n") 
        // @author: Klemen Nagode 
        // @source: http://***.com/questions/1269562/how-to-create-an-array-from-a-csv-file-using-php-and-the-fgetcsv-function
        $array = array();
        $size = strlen($string);
        $columnIndex = 0;
        $rowIndex = 0;
        $fieldValue="";
        $isEnclosured = false;
        for($i=0; $i<$size;$i++) 

            $char = $string$i;
            $addChar = "";

            if($isEnclosured) 
                if($char==$enclosureChar) 

                    if($i+1<$size && $string$i+1==$enclosureChar)
                        // escaped char
                        $addChar=$char;
                        $i++; // dont check next char
                    else
                        $isEnclosured = false;
                    
                else 
                    $addChar=$char;
                
            else 
                if($char==$enclosureChar) 
                    $isEnclosured = true;
                else 

                    if($char==$separatorChar) 

                        $array[$rowIndex][$columnIndex] = $fieldValue;
                        $fieldValue="";

                        $columnIndex++;
                    elseif($char==$newlineChar) 
                        echo $char;
                        $array[$rowIndex][$columnIndex] = $fieldValue;
                        $fieldValue="";
                        $columnIndex=0;
                        $rowIndex++;
                    else 
                        $addChar=$char;
                    
                
            
            if($addChar!="")
                $fieldValue.=$addChar;

            
        

        if($fieldValue)  // save last field
            $array[$rowIndex][$columnIndex] = $fieldValue;
        


        /**
         * Skip rows. 
         * Returning empty array if being told to skip all rows in the array.
         */ 
        if ($skip_rows > 0) 
            if (count($array) == $skip_rows)
                $array = array();
            elseif (count($array) > $skip_rows)
                $array = array_slice($array, $skip_rows);           

        

        return $array;
    

【讨论】:

在***中,请详细说明而不是只提供链接。【参考方案8】:

此函数将返回带有 Header 值的数组作为数组键。

function csv_to_array($file_name) 
        $data =  $header = array();
        $i = 0;
        $file = fopen($file_name, 'r');
        while (($line = fgetcsv($file)) !== FALSE) 
            if( $i==0 ) 
                $header = $line;
             else 
                $data[] = $line;        
            
            $i++;
        
        fclose($file);
        foreach ($data as $key => $_value) 
            $new_item = array();
            foreach ($_value as $key => $value) 
                $new_item[ $header[$key] ] =$value;
            
            $_data[] = $new_item;
        
        return $_data;
    

【讨论】:

【参考方案9】:

试试这个..

function getdata($csvFile)
    $file_handle = fopen($csvFile, 'r');
    while (!feof($file_handle) ) 
        $line_of_text[] = fgetcsv($file_handle, 1024);
    
    fclose($file_handle);
    return $line_of_text;



// Set path to CSV file
$csvFile = 'test.csv';

$csv = getdata($csvFile);
echo '<pre>';
print_r($csv);
echo '</pre>';

Array
(
    [0] => Array
        (
            [0] => Project
            [1] => Date
            [2] => User
            [3] => Activity
            [4] => Issue
            [5] => Comment
            [6] => Hours
        )

    [1] => Array
        (
            [0] => test
            [1] => 04/30/2015
            [2] => test
            [3] => test
            [4] => test
            [5] => 
            [6] => 6.00
        ));

【讨论】:

【参考方案10】:

要获得具有正确键的数组,您可以试试这个:

// Open file
$file = fopen($file_path, 'r');

// Headers
$headers = fgetcsv($file);

// Rows
$data = [];
while (($row = fgetcsv($file)) !== false)

    $item = [];
    foreach ($row as $key => $value)
        $item[$headers[$key]] = $value ?: null;
    $data[] = $item;


// Close file
fclose($file);

【讨论】:

【参考方案11】:

我想出了这个非常基本的代码。我认为它对任何人都有用。

$link = "link to the CSV here"
$fp = fopen($link, 'r');

while(($line = fgetcsv($fp)) !== FALSE) 
    foreach($line as $key => $value) 
        echo $key . " - " . $value . "<br>";
    



fclose($fp);

【讨论】:

【参考方案12】:

如果您希望每一行都在一个数组中,并且该行中的每个单元格都在数组中:

$file = fopen('csvFile.csv', 'r');              // Open the file                     
while (($line = fgetcsv($file)) !== FALSE)     // Read one line
    $array[] =$line;                            // Add the line in the main array

echo '<pre>';
print_r($array);   //print it out
echo '</pre>'; 
fclose($file);

【讨论】:

【参考方案13】:
 function csvToArray($path)

    try
        $csv = fopen($path, 'r');
        $rows = [];
        $header = [];
        $index = 0;
        while (($line = fgetcsv($csv)) !== FALSE) 
            if ($index == 0) 
                $header = $line;
                $index = 1;
             else 
                $row = [];
                for ($i = 0; $i < count($header); $i++) 
                    $row[$header[$i]] = $line[$i];
                
                array_push($rows, $row);
            
        
        return $rows;
    catch (Exception $exception)
        return false;
    

【讨论】:

【参考方案14】:
convertToArray(file_get_content($filename));

function convertToArray(string $content): array

   $data = str_getcsv($content,"\n");
   array_walk($data, function(&$a) use ($data) 
       $a = str_getcsv($a);
   );

   return $data;

【讨论】:

有什么问题? 见“Explaining entirely code-based answers”。虽然这在技术上可能是正确的,但它并不能解释为什么它可以解决问题或应该是选择的答案。除了帮助解决问题,我们还应该进行教育。【参考方案15】:

我在 PHP 中创建了一个实用程序,可以将 CSV 数据从文件或字符串转换为对象数组,还提供了按特定列对项目进行分组的选项,您还可以将分隔符从逗号更改为任何你想要的角色。

例子:

Brand, Model, Year
Volkswagen, Gol,2008
Fiat, Uno, 2007
Fiat, Palio, 2002
Fiat, Mobi, 2021
Volkswagen, Jetta, 2018
Hyunday, HB20, 2020

返回: Array made out of CSV

按示例分组:

Grouping by the 'Brand' column

Grouping by the 'Year' column

您可以在这里找到代码:https://github.com/raphah96/PHPCSV

我经常使用 CSV,这就是为什么我必须制作一个一致的实用程序而不是简单的一次性代码。

【讨论】:

以上是关于如何使用 PHP 和 fgetcsv 函数从 CSV 文件创建数组的主要内容,如果未能解决你的问题,请参考以下文章

php 上传csv文件

php读取csv文件时 用phpexcel很慢 用fgetcsv()函数中文乱码 请问还有啥excel库或函数方法来读csv文件吗

fgetcsv()函数

PHP CSV,如何从当前行获取前三行和后三行

通过php访问时csv文件的偏移量?

php fgetcsv() 行以逗号分隔符结尾