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.
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
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);
Related
I have a file input.txt that contains file names that I need to open and read data. I have written the following php code and I get the failed to open stream: No such file or directory when it tries to open with variable $files, i.e., the second fopen is failing.
$handle = fopen("/home/user/input.txt", "r");
if($handle) {
while(($files = fgets($handle)) !== false) {
print $files;
$filename = fopen($files,"r");
print $filename;
}
}
input.txt content:
/home/user/file_1
/home/user/file_2
/home/user/file_3
/home/user/file_4
file_1,file_2,file_3 and file_4 are in /home/user/
I am not sure what I am doing wrong.
My guess is that the file lines contains whitespaces (e.g. \r), to remove them we'll use trim()
function open_files_from_file_list()
{
$handle = fopen("/home/user/input.txt", "r");
if(!$handle)
return;
while(($line = fgets($handle)) !== false)
{
$line=trim($line);
print $line;
if (!file_exists($line))
{
print ' does not exists';
continue;
}
$filename = fopen($line,"r");
print $filename;
}
}
I have a csv file that is 2Mb size, and has pipe delimiter. I would like to take the first row and replace its data then resave the file. Here is what I did :
//Creating a new first row with the modified data.
$file = fopen($path,"r");//$path is where the file is located : outputs/my_file.csv
$size = filesize($path);
$firstLine = fgetcsv(fopen($path,"r")); //$firstLine has all the data of the first row as array
fclose($file);
$firstLine = explode("|", $firstLine[0]);//To get each column row
$newHeader = array();
for($i = 0; $i<sizeof($firstLine ); $i++){
if($i == 4){
array_push($newHeader, "modified column in row 1 ");//Only column 4 in row 1 is modified
}else{
array_push($newHeader, $firstLine [$i]);
}
}
$Header = implode("|", $newHeader);
//Creating the new csv file
$row = 0;
while (($data = fgetcsv(fopen($path,"r"), "|")) !== false) {
if($row == 0){
$data[0] = $Header;
}
$newCsvData[] = $data;
}
return $newCsvData; //I wanted to display the new content of the csv before saving it
This code should print the new content of the csv file that I will store but I get an error : Allowed memory size of 536870912 bytes exhausted (tried to allocate 332 bytes) How can I do that in a very fast way ? the file is about 19122 row.
Thanks
If it's only 2mb, maybe read the entire file into memory and then write out a new file (overwriting the previous file). Here are some helper functions to help you read and write the file, and I'm certain you're proficient in editing the resulting array:
/**
* Reads a file into an array
*
* #param $FILE string the file to open
*
* #return $lines The Lines of the file as an array
*/
public static function readFile($FILE) {
$lines = array(); // the array to store each line of the file in
$handle = fopen($FILE, "r");
if ($handle) {
// $FILE successfully opened for reading,
while (($line = fgets($handle)) !== false) {
$lines[] = $line; //add each line of the file to $lines
}
} else {
throw new Exception("error opening the file...");
}
fclose($handle); // close the file
return $lines; // return the lines of the file as an array
}
/**
* Writes the $lines of a file into $FILE
*
* #param $FILE string The file to write
* #param $lines array An array containing the lines of the file
*
* #return $result int|NULL The number of bytes written, or null on failure. See: php.net/fwrite#refsect1-function.fwrite-returnvalues
*/
public static writeFile($FILE, $lines) {
// Add newline at the end of each line of the array
// output is now a single string which we will write in one pass
// (instead of line-by-line)
$output = implode("\n", $lines);
$handle = fopen($FILE, "w+");
if ($handle) {
// $FILE successfully opened for writing, write to the file
$result = fwrite($handle, $output);
} else {
throw new Exception("error opening the file...");
}
fclose($handle); // close the file
return $result; // The number of bytes written to the file, or NULL on failure
}
<?php
$source = fopen('filename','r');
$destination = fopen('newfilename','w');
//write new header to new file
fwrite($destination,"your|replacement|header\n");
//set the pointer in the old file to the second row
fgets($source);
//copy the entire stream
stream_copy_to_stream($source,$destination);
//rename the newfilename to the old filename
rename('newfilename','filename');
//check what memory we used:
var_dump(memory_get_peak_usage());
That resulted in 142260 bytes used of memory at its peak for a 2MB file. BTW: the memory usage of a 2GB file is exactly if I test it here.
I'm currently opening a TAB delimited file with the following code...
if (($handle = fopen($filetxt, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 0, "\t")) !== FALSE) {
// var_dump($data);
$num = count($data);
echo "<br>\n";
$row++;
for ($c=0; $c < $num; $c++) {
echo $data[$c] . "<br />\n";
}
}
fclose($handle);
}
Now I'm just trying to figure out how I can put the data into a CSV using fputcsv. An example would be great -- right now I'm just trying to get the headers into a CSV and then I can go from there.
The data right now (that's being echoed) looked like this...
part_number
aaia_part_term_id
short_description
bullet_points
list_price
jobber_price
base_price
epc_code
length
width
height
weight
image_name
If I could just figure out how to echo only the header into the CSV, I think I can figure out the rest.
fopen only gives you a handle to the file. A csv file's formatting relies going through each line, the way you are reading the file uses all contents at once, try:
<?PHP
if($handle = fopen($filetext, "r") !== FALSE){
while (!feof($handle)) {
$line_of_text = fgets($handle);
foreach( fgetcsv($line_of_text, 0, "\t") as $csv_item)
print $csv_item."," ;
print "<br>";
}
fclose($handle);
}
?>
I haven't tested this
Since a CSV file is just a comma delimited data file, it might be simpler just to read the current tab-delimited file line by line, and replace tabs with commas
if (($handle = #fopen($filetxt, "r")) !== false) {
while (($line = fgets($handle, 0)) !== false) {
$csv_line = str_replace("\t", ",", $line);
// write $csv_line to your csv file
}
fclose($handle);
}
I want to create a command line php script which would merge/join multiple CSV files from a folder into one.
Each CSV file has 2 columns delimited by comma (,) but multiple number of rows varies. Also each of the CSV file name is unique so when we merge the CSV files I want the file name of the CSV to be the first column for each rows in the file.
So eventually when the script it run it’ll join multiple CSV files under a folder to one. From 2 columns the output file will have 3 columns where the first column would be the file name.
<?php
$nn = 0;
foreach (glob("*.csv") as $filename) {
if (($handle = fopen($filename, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 0, ",")) !== FALSE) {
$c = count($data);
$csvarray[$nn][] = $filename;
for ($x=0;$x<$c;$x++)
{
$csvarray[$nn][] = $data[$x];
}
$nn++;
}
fclose($handle);
}
}
$fp = fopen('../file.csv', 'w');//output file set here
foreach ($csvarray as $fields) {
fputcsv($fp, $fields);
}
fclose($fp);
?>
I didn't make any test on it though, here is the logic and code you can follow.
there are two columns in my csv file,eg:
image gallery
/1.jpg /a.jpg;/b.jpg
..... .....
now i want to update the gallery content to /1.jpg;/a.jpg;/b.jpg. namely,add the content of image collumn and ; to the gallery content.
the following is my code.when i run it. it can't update the content of the csv.i am get stucked.
$dir = getcwd();
$files = scandir($dir);
foreach ($files as $file) {
$parts = pathinfo($file);
if ($parts['extension']!="csv") {
continue;
}
if (($handle = fopen($file, "r")) !== FALSE) {
while (($data = fgetcsv($handle, 4096, ",")) !== FALSE) {
$data[1]=$data[0].";".$data[1];
fputcsv($file, $data);
}
fclose($handle);
}
open file in write or append mode and
fputcsv expects first parameter to be resource and you have given file path
which is causing problem
change it
fputcsv($handle, $data);
Please check the file permission first and after that you have to change the handle to both read and write and also please check whether the data[1] is having the values.
Because in Your code the the data[0] only will fetch the lines as a string which is separated with ";" so you have to explode it and after that do the operations.