Cómo crear una matriz a partir de un archivo CSV usando PHP y la función fgetcsv


106

¿Puede alguien proporcionar amablemente un código para crear una matriz a partir de un archivo CSV usando fgetcsv?

He usado el siguiente código para crear una matriz a partir de un archivo CSV simple, pero no funciona bien cuando uno de mis campos tiene varias comas, como direcciones.

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

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

* Además, str_getcsv no es compatible con mi servicio de alojamiento.

El código anterior no funciona con el siguiente ejemplo de archivo CSV. La primera columna es el nombre, la segunda columna es la dirección, la tercera columna es el estado civil.

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
Atascado con PHP 5.2, ¿eh? Lo siento por ti, estoy en el mismo barco que mi proveedor de hosting.
Adam F

Respuestas:


179

Como dijiste en tu título, fgetcsv es el camino a seguir. Es bastante fácil de usar.

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

Querrá poner más verificación de errores allí en caso de que fopen()falle, pero esto funciona para leer un archivo CSV línea por línea y analizar la línea en una matriz.


Gracias Dave, pero tu ejemplo solo proporciona una matriz con las siguientes tres posiciones: $ línea [0], $ línea [1] y $ línea [2]. Eso está bien para la primera línea, pero necesito crear posiciones separadas para las líneas 2, 3, 4, etc. De esa forma puedo manipular las líneas por separado. Espero que tenga sentido
Thomas

7
@Thomas Si necesita una variedad de nombres, direcciones y estados, puede hacer lo que está haciendo arriba: list($names[], $addresses[], $statuses[]) = $line;
Dave DeLong

¡Gracias de nuevo Dave! Eso me estaba haciendo tropezar.
Thomas

Tengo una pregunta sobre esta función, si uno de los campos CSV tiene una nueva línea, ¿analizará actualmente la línea como un solo registro? ¿O devolverá dos registros (destrozados) en su lugar?
Alix Axel

¿Por qué tenemos que cerrar al final?
kiwi enojado

55

Creo que la sintaxis str_getcsv () es mucho más limpia, tampoco requiere que el CSV se almacene en el sistema de archivos.

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

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

O para una solución línea por línea:

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

O para una solución línea por línea sin 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
FYI: str_getcsv () solo está disponible desde PHP 5.3.0 en adelante. ¡El proyecto en el que estoy trabajando se perdió por 1 versión DOH! (estamos usando 5.2.9 atm).
Jim Ford

Eso es excelente, a menos que tenga restricciones de memoria. La solución fgetcsv funciona con cualquier configuración de hardware.
Sp4cecat

4
¡TENER CUIDADO! hay un error con str_getcsv que hace que ignore los finales de línea: bugs.php.net/bug.php?id=55763&edit=1
RJD22

Tenga en cuenta que puede hacer: while (! Feof ($ archivo)) {$ csv [] = fgetcsv ($ archivo); } en lugar de while (($ resultado = fgetcsv ($ archivo))! == falso) {$ csv [] = $ resultado; }
David G

23

He creado una función que convertirá una cadena csv en una matriz. La función sabe cómo escapar de los caracteres especiales y funciona con o sin caracteres delimitados.

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

¡Lo probé con su muestra de csv y funciona como se esperaba!

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
Pulgares arriba por la simplicidad
kudlohlavec

14

Pregunta antigua, pero aún relevante para los usuarios de PHP 5.2. str_getcsv está disponible desde PHP 5.3. Escribí una pequeña función que funciona con fgetcsv.

A continuación se muestra mi función de 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;
}

Devoluciones

Comenzar a leer 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
        )
) 

Por cierto, puede agregar parámetros opcionales a fgetcsv para cambiar el delimitador, el carácter del recinto, etc.
Manu Manjunath

4

Prueba esto..

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

Esta función devolverá una matriz con valores de encabezado como claves de matriz.

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

Para obtener una matriz con las claves correctas, puede intentar esto:

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

Encuentre debajo un enlace a la función de @knagode, mejorado con un parámetro de omisión de filas. 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
En stackoverflow, proporcione más detalles en lugar de proporcionar solo un enlace.
Paul Lo

1

Se me ocurrió este código bastante básico. Creo que podría ser útil para cualquiera.

$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

Si desea que cada línea esté en una matriz y cada celda de la línea en una matriz:

$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

Prueba este código:

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

1
¿Cuál es la razón para publicar exactamente la misma respuesta aplicada?
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;
}

¿cuál es la pregunta?
SpongePablo

Consulte " Explicación de respuestas totalmente basadas en códigos ". Si bien esto puede ser técnicamente correcto, no explica por qué resuelve el problema o debería ser la respuesta seleccionada. Debemos educar además para ayudar a resolver el problema.
The Tin Man
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.