Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove specific line from CSV file by its line number?

Tags:

php

csv

I'm trying to delete one line from CSV file by its line number, which I get as a parameter in URL.

I saw some discussions here, but it was mainly "delete a line by its id stored in first column" and so on. I tried to make it in the same way as others in these discussions, but it does not work. I only changed the condition.

if (isset($_GET['remove']))
{
    $RowNo = $_GET['remove'];   //getting row number
    $row = 1;
    if (($handle = fopen($FileName, "w+")) !== FALSE)
    {
        while (($data = fgetcsv($handle, 1000, ";")) !== FALSE)
        {
//Here, I don't understand, why this condition does not work.
            if ($row != $RowNo)
            {
                fputcsv($handle, $data, ';');
            }
            $row++;
        }
        fclose($handle);
    }
}

I supposed, that it should work for me too, BCS just condition was changed. But it does not. It clears the whole file. Could you help me with it, please?

Thank you very much for any advice. Daniel.

like image 215
Daniel Vácha Avatar asked Oct 12 '25 21:10

Daniel Vácha


2 Answers

You could load the file as an array of lines by using file().

Then remove the line and write the file back.

// read the file into an array    
$fileAsArray = file($FileName);

// the line to delete is the line number minus 1, because arrays begin at zero
$lineToDelete = $_GET['remove'] - 1;

// check if the line to delete is greater than the length of the file
if ($lineToDelete > sizeof($fileAsArray)) {
    throw new Exception("Given line number was not found in file.");
}

//remove the line
unset($fileAsArray[$lineToDelete]);

// open the file for reading
if (!is_writable($fileName) || !$fp = fopen($fileName, 'w+')) {
    // print an error
    throw new Exception("Cannot open file ($fileName)");
}

// if $fp is valid
if ($fp) {
    // write the array to the file
    foreach ($fileAsArray as $line) {
        fwrite($fp, $line);
    }

    // close the file
    fclose($fp);
}

If you have a unix system you could also use sed command:

exec("sed -e '{$lineToDelete}d' {$FileName}");

Remember cleaning command parameters if user input used: https://www.php.net/manual/de/function.escapeshellcmd.php

like image 82
Florian Gee Avatar answered Oct 14 '25 16:10

Florian Gee


Option if your CSV can fit to memory:

// Read CSV to memory array
$lines = file($fileName, FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES);

// Remove element from array
unset($lines[$rowNo - 1]); // Validate that element exists!

// Rewrite your CSV file
$handle = fopen($fileName, "w+");

for ($i = 0; $i < count($lines); $i++) {
    fputcsv($handle, $data, ';');
}

fclose($handle);

Option if your CSV can not fit to memory:

Use code from question, just write to separate file and later replace it with actual file:

$handle = fopen($FileName, "r");

 // Read file wile not End-Of-File
 while (!feof($fn)) {
    if ($row != $RowNo) {
        file_put_contents($FileName . '.tmp', fgets($fn), FILE_APPEND);
    }

    $row++;
}

fclose($handle);

// Remove old file and rename .tmp to previously removed file
unlink($FileName);
rename($FileName . '.tmp', $FileName);
like image 23
Justinas Avatar answered Oct 14 '25 16:10

Justinas