Как создать массив из файла CSV с помощью PHP и функции fgetcsv

106

Может ли кто-нибудь любезно предоставить код для создания массива из файла CSV с помощью fgetcsv?

Я использовал следующий код для создания массива из простого 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
Томас
источник
2
Застрял с PHP 5.2, а? Я сочувствую вам, я нахожусь в одной лодке с моим хостинг-провайдером.
Adam F
Вы можете использовать этот помощник: github.com/rap2hpoutre/csv-to-associative-array
rap-2-h

Ответы:

179

Как вы сказали в заголовке, 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 по строке и синтаксического анализа строки в массив.

Дэйв Делонг
источник
Спасибо, Дэйв, но ваш пример предоставляет только массив со следующими тремя позициями: $ line [0], $ line [1] и $ line [2]. Это нормально для первой строки, но мне нужно создать отдельные позиции для 2-й, 3-й, 4-й и т. Д. Строк. Таким образом я могу управлять линиями по отдельности. Надеюсь, это имеет смысл
Томас
7
@Thomas Если вам нужен массив имен, адресов и статусов, вы можете просто сделать то, что вы делаете выше: list($names[], $addresses[], $statuses[]) = $line;
Дэйв Делонг,
Еще раз спасибо, Дэйв! Это меня сбивало с толку.
Thomas
У меня есть вопрос об этой функции: если в одном из полей CSV есть новая строка, будет ли она сейчас анализировать строку как отдельную запись? Или вместо этого он вернет две (искаженные) записи?
Аликс Аксель
почему нам нужно закрыть в конце?
злой киви
55

Я думаю, что синтаксис 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>';
Аликс Аксель
источник
2
К вашему сведению: str_getcsv () доступен только с PHP 5.3.0. Проект, над которым я работаю, пропустил его на 1 версию DOH! (мы используем 5,2,9 атм).
Джим Форд,
Это отлично, если у вас нет ограничений по памяти. Решение fgetcsv работает с любой конфигурацией оборудования.
Sp4cecat
4
ОСТОРОЖНО! в str_getcsv есть ошибка, из-за которой он игнорирует окончания строк: bugs.php.net/bug.php?id=55763&edit=1
RJD22,
Обратите внимание, что вы можете сделать: while (! Feof ($ file)) {$ csv [] = fgetcsv ($ file); } вместо while (($ result = fgetcsv ($ file))! == false) {$ csv [] = $ result; }
David G
23

Я создал функцию, которая преобразует строку 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;
}
кнагод
источник
16
$arrayFromCSV =  array_map('str_getcsv', file('/path/to/file.csv'));
Иван Г
источник
1
Большой палец
14

Старый вопрос, но все еще актуален для пользователей 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 для изменения разделителя, символа вложения и т. Д.
Ману Манджунатх
4

Попробуй это..

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
        ));
Динадхаялан Манохаран
источник
3

Эта функция вернет массив со значениями заголовка в виде ключей массива.

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;
    }
Самеерали
источник
3

Чтобы получить массив с правильными ключами, вы можете попробовать следующее:

// 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);
Clem
источник
1

Пожалуйста, найдите ссылку на функцию из @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://stackoverflow.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;
    }
Габриэль
источник
1
В stackoverflow просьба уточнить подробности, а не только ссылку.
Пол Ло
1

Я придумал этот довольно простой код. Думаю, это может быть полезно кому угодно.

$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);
grc
источник
1

Если вы хотите, чтобы каждая строка была в массиве, а каждая ячейка в строке в массиве:

$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);
Для блага
источник
0

Попробуйте этот код:

function readCsv($file)
{
    if (($handle = fopen($file, 'r')) !== FALSE) {
        while (($lineArray = fgetcsv($handle, 4000)) !== FALSE) {
            print_r(lineArray);
        }
        fclose($handle);
    }
}
Индраджит Сингх
источник
1
Какова причина публикации того же самого ответчика, задавшего вопрос?
pinepain
0
 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;
    }
}
гак
источник
0
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;
}
Камил Сулек
источник
Что за вопрос?
Губка Пабло
См. « Объяснение ответов на основе кода ». Хотя это может быть технически правильным, но не объясняет, почему он решает проблему или должен быть выбранным ответом. Мы должны обучать в дополнение к помощи в решении проблемы.
Железный Человек