Jak utworzyć tablicę z pliku CSV za pomocą PHP i funkcji fgetcsv


106

Czy ktoś może uprzejmie dostarczyć kod do utworzenia tablicy z pliku CSV przy użyciu fgetcsv?

Użyłem następującego kodu, aby utworzyć tablicę z prostego pliku CSV, ale nie działa poprawnie, gdy jedno z moich pól zawiera wiele przecinków - na przykład adresy.

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

foreach($lines as $data)
{
list($name[],$address[],$status[])
= explode(',',$data);
}

* Ponadto moja usługa hostingowa nie obsługuje str_getcsv.

Powyższy kod nie działa z następującym przykładem pliku CSV. Pierwsza kolumna to nazwisko, druga adres, trzecia to stan cywilny.

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
Utknąłeś z PHP 5.2? Współczuję wam, jestem na tej samej łodzi z moim dostawcą usług hostingowych.
Adam F

Możesz skorzystać z tego pomocnika: github.com/rap2hpoutre/csv-to-associative-array
rap-2-h

Odpowiedzi:


179

Jak powiedziałeś w swoim tytule, fgetcsv jest drogą do zrobienia. Jest bardzo łatwy w użyciu.

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

Będziesz chciał umieścić tam więcej sprawdzania błędów na wypadek fopen()niepowodzenia, ale to działa, aby odczytać plik CSV wiersz po wierszu i przeanalizować wiersz do tablicy.


Dzięki, Dave, ale twój przykład zawiera tylko tablicę z następującymi trzema pozycjami: $ line [0], $ line [1] i $ line [2]. To jest w porządku dla pierwszej linii, ale muszę utworzyć osobne pozycje dla drugiej, trzeciej, czwartej itd. Linii. W ten sposób mogę osobno manipulować liniami. Mam nadzieję, że to ma sens
Thomas

7
@Thomas Jeśli potrzebujesz tablicy nazwisk, adresów i statusów, możesz po prostu zrobić to, co robisz powyżej: list($names[], $addresses[], $statuses[]) = $line;
Dave DeLong

Jeszcze raz dziękuję Dave! To mnie podrywało.
Thomas

Mam pytanie dotyczące tej funkcji, jeśli jedno z pól CSV ma w sobie nową linię, czy będzie ona obecnie analizować linię jako pojedynczy rekord? Czy zamiast tego zwróci dwa (zniekształcone) rekordy?
Alix Axel

dlaczego musimy zamknąć na końcu?
angry kiwi

55

Myślę, że składnia str_getcsv () jest znacznie czystsza, nie wymaga również przechowywania pliku CSV w systemie plików.

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

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

Lub w przypadku rozwiązania linia po linii:

$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>';

Lub dla rozwiązania linia po linii bez 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
Do Twojej wiadomości: str_getcsv () jest dostępna tylko od PHP 5.3.0. Projekt, nad którym pracuję, przegapił 1 wersję DOH! (używamy 5,2,9 atm).
Jim Ford

To świetnie, chyba że masz ograniczenia pamięci. Rozwiązanie fgetcsv działa z każdą konfiguracją sprzętową.
Sp4cecat

4
STRZEC SIĘ! w str_getcsv jest błąd, który powoduje, że ignoruje ono zakończenia linii: bugs.php.net/bug.php?id=55763&edit=1
RJD22

Zauważ, że możesz: while (! Feof ($ file)) {$ csv [] = fgetcsv ($ file); } zamiast while (($ wynik = fgetcsv ($ plik))! == false) {$ csv [] = $ wynik; }
David G.

23

Stworzyłem funkcję, która skonwertuje ciąg csv na tablicę. Funkcja wie, jak unikać znaków specjalnych i działa ze znakami obudowy lub bez.

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

Wypróbowałem to z twoją próbką CSV i działa zgodnie z oczekiwaniami!

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;
}


14

Stare pytanie, ale nadal aktualne dla użytkowników PHP 5.2. str_getcsv jest dostępny od PHP 5.3. Napisałem małą funkcję, która działa z samym fgetcsv.

Poniżej moja funkcja z 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;
}

Zwroty

Rozpocznij czytanie 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
        )
) 

Przy okazji, możesz dodać opcjonalne parametry do fgetcsv, aby zmienić ogranicznik, znak obudowy itp.
Manu Manjunath

4

Spróbuj tego..

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

Ta funkcja zwróci tablicę z wartościami nagłówka jako klucze tablicy.

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

Aby uzyskać tablicę z odpowiednimi kluczami, możesz spróbować tego:

// 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);

1

Poniżej znajduje się link do funkcji z @knagode, wzbogaconej o parametr pomijania wierszy. 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
W przypadku przepełnienia stosu prosimy o więcej informacji niż podawanie samego łącza.
Paul Lo

1

Wymyśliłem ten dość podstawowy kod. Myślę, że może się przydać każdemu.

$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);

1

Jeśli chcesz, aby każda linia była w tablicy, a każda komórka w linii w tablicy:

$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

Wypróbuj ten kod:

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

1
Jaki jest powód, aby opublikować dokładnie taką samą odpowiedź, jaka została zastosowana?
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;
}

Jakie jest pytanie?
SpongePablo

Zobacz „ Wyjaśnianie odpowiedzi opartych wyłącznie na kodzie ”. Chociaż może to być technicznie poprawne, nie wyjaśnia, dlaczego rozwiązuje problem lub powinno być wybraną odpowiedzią. Powinniśmy dodatkowo kształcić, aby pomóc rozwiązać problem.
Tin Man
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.