PHP write to file without last newline - php

I want to read a CSV data file, load it into an array, edit it and write it back to a file. I have been able to accomplish this a single iteration with examples here on Stackoverflow! Thanks.
The trouble is when I write the new data back to the file, both methods I have tried to write the edited Array back to the file add an newline at the end the file. This creates an issue when loading the CSV file data a 2nd time. The 2nd read causes an empty Index in the Array that causes an error when writing the file.
Example #1:
foreach($editArray as $row) {
$writeStuff = implode(",", $row);
fwrite($file_handle, $writeStuff);
fwrite($file_handle, "\n");
}
Example #2:
foreach ($editArray as $row) {
fputcsv($file_handle, $row);
}
This is the original csv data:
1/1/16,Yes,No
1/2/16,No,Yes
When written using the above it produces this data with the added newline:
1/1/16,Yes,No
1/2/16,No,Yes
This extra new line creates an issue when reading the file a 2nd time. I get an error on both the fputcsv() or implode(). I believe it is because the empty Index caused by the newline when I read the file the 2nd time after the first write.
I could use a for loop with a conditional on the last fwrite() in the implode() Example #1, but that would seem clunky and not the way to do it.
Maybe there is a completely different way to handle this?

This is the expected behaviour of fputcsv
fputcsv() formats a line (passed as a fields array) as CSV and write it (terminated by a newline) to the specified file handle.
Being that all lines are terminated by newline, you will have an extra blank line at the end of the file
You should apply a fix for the second read, where the last line creates issues, by checking if the line is empty before processing.

If you want to prevent adding a new line at the end of the file, you could build your data set with new lines where you need them (and where you don't) then write it once:
$writeStuff = [];
foreach($editArray as $row) {
$writeStuff[] = implode(',', $row);
}
fwrite($file_handle, implode(PHP_EOL, $writeStuff));
Also, I'm not sure how you load the file, but you could always skip empty lines - here's an example:
$editArray = file('your_filename.csv', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

Based upon the recommendation, I looked for a solution when reading and loading the file rather than when I wrote the file.
These are the solutions I came up with.
First Option:
while(! feof($file_handle)) {
$tmp = fgetcsv($file_handle);
if($tmp != NULL) {
$myArray[] = $tmp;
}
}
fgetcsv returns a NULL if the line is empty.
Second Option. Ditch the fgetcsv() for file(). It ignores the empty newline without testing.
$data_Array = file($file);
foreach($$data_Array as $key) {
$myArray[] = explode(",", $key);
}
This seems to work. Additionally the example given earlier with implode() and PHP_EOL seems to work also. I may be missing something, but these work for now.

Related

How to delete array in text file PHP

I have a text file. I want to delete some lines with a query of search.
The array is line by line. I want to made it like http://keywordshitter.com/
The logic is,
SEARCH --> IN ARRAY --> OUTPUT IS ARRAY WITHOUT "QUERY OF SEARCH"
Code I have tried:
$fileset = file_get_contents("file.txt");
$line = explode("\n", $fileset);
$content = array_search("query",$line);
print_r($content);
MY file.txt
one
two
three
apple
map
I have used array_search but not working.
you can do search like
$fileset=file("file.txt"); // file function reads entire file into an array
$len=count($fileset);
for($i=0;$i<$len;$i++)
{
if($fileset[$i]=="query")
{
$fileset[$i]="";
break; //then we will stop searching
}
}
$fileset_improve=implode($fileset); //this will again implode your file
$handle=fopen("file.txt","w"); //opening your file in write mode
fwrite($handle,$fileset_improve); //writing file with improved lines
fclose($handle); //closing the opened file
remember this lines will make your search line blank....
if you wanna then you can arrange whole array i.e. shifting following indexed data to previous index to decrease line counts but this will increase your programming complexity.
Hope this will work for you.
Thanks
Use PHP_EOL on your explode function instead of "\n". PHP_EOL will handle the correct line break character(s) of the server platform.

Storing last line of file in an array continuously in PHP

So i have a little issue with some PHP read functionality. What I am trying to do is basically grab data into an array from a file that is being continuously updated from a python script reading values from a micro controller. So basically, the file would look something like this.
ID, Datetime, Count, Name
ID, Datetime, Count, Name
ID, Datetime, Count, Name
What i need is for it to read the new line that is being added in (eof) and store it into an array. So what i have so far is allowing read access into the file
<?php
$myfile = fopen("read.txt", "r")
For the storing the lines in an array i figured something like an array map would be efficient
$result = array();
// some loop
$parts = array_map('trim', explode(':', $line_of_text, 2)));
$result[$parts[0]] = $parts[1];
However i am not to sure on how to structure the loop to have it read the new line that is being updated in the file without exiting the loop.
while (feof($file)) {
}
fclose($file);
?>
Any help would be appreciated!!
Can you do this?
Read the lines of the file to an array using $lines = file("filename");.
Use the $lines[count($lines) - 1] to get the last line?
You can even trim off the empty lines before you wanna do this.
Trim Empty Lines
Use this function:
$lines = array_filter($lines);
Since the file is continually being appended, you'd have to read until you hit the end of file, sleep for a while to let more data be appended, then read again.
e.g.
while(true) {
while(!feof($file)) {
... process data
}
sleep(15); // pause to let more data be appended
}
However, I'm not sure if PHP will cache the fact that it hit eof, and not try again once the sleep() finishes. It may be necessary to record your current position ftell(), close the file, reopen it, then fseek() to the stored location.
I've came up with this solution
$filename = "file.txt";
$file = fopen($filename, "r");
$lines = explode("/n", fread($file, filesize($filename)));
$last = $lines[count($lines)-1];
If the file is going to get big, it could take some time to parse, so its also possible to adjust the fread() function so it only reads the last 100 characters for example.

PHP SplFileObject error

Wanted to seperate each line in the text file, reverse the order and echo it.
Got Method SplFileObject::__toString() must return a string value error.
Here's the code:
for ($x=$lines; $x>0; $x--) {
$file = new SplFileObject("post.txt");
$file -> seek($x);
echo $file;
}
I would use good old file() together with array_reverse():
foreach(array_reverse(file('file.txt')) as $line) {
echo $line;
}
You're simply seeking to a line longer than the file you've input.
This is an issue for you with these files, because you won't know how many lines are in a file until you've iterated to the end. A text file's number of lines isn't something stored in the file's metadata - it's not like the filesize. SplFileObject is intended to use its iterator, which can only seek() (go forward from the start to a specific line -- fairly slow if you're reversing lines this way), next(), or rewind() (go back to the start). It's an excellent class to use if you want to read through a file, but not great for going backwards the way you've indicated.
To get lines backwards from the end, you'll want to use an array where each item is a line in your file. That's the intended use of the old builtin file ( http://php.net/manual/en/function.file.php ).
If your heart is set on an SplFileObject, because you want to use it elsewhere in your code, you can build an array in reverse like so:
$lines = [];
foreach (new SplFileObject('test.txt') as $line) {
array_unshift($lines, $line);
}
echo implode('', $lines);

Read a csv file and create another csv file using php

I have a .csv file and when I open it via notepad it looks like:
ID501501503502
And when I print it in the browser via php, it looks like
ID 501 501 503 502
My code is:
$handle = fopen("MonC1.csv", "r");
$data = fgetcsv($handle, 0);
$fh = fopen('php://output', 'w');
if (! empty($data)) {
foreach ($data as $item) {
echo $item."<br>";
//fputcsv($fh, array($item));
}
}
So basically the br tag inside the for loop doesn't work.This is my first problem.
And the second problem is even if I use fputcsv(now it is turned off) it doesn't create a actual csv file.
Now my question is how come it has got no space in notepad and when I print in browser it gets space?
I have only one column and nothing else.
Any help is highly appreciated. Thanks in advance.
As mentioned in my comment, it looks like your original file is saved with UNIX line endings, and then you're using fgetcsv in Windows, so the whole file is being read as one line. There's probably one <br> at the end of the whole output.
So before processing your file, you'll need to preprocess it to convert the line endings.
On Linux, the utility unix2dos does what you want. Or, you can simply replace \n with \r\n in your file.
The other problem is that fgetcsv does not turn an entire file into an array. Instead, it reads a single line from your file handle, and converts that to an array. You'll need to read lines inside a loop:
while (($data = fgetcsv($handle)) !== FALSE) {
// $data contains one line of the CSV, in array form
// now you can fputcsv the single line
}

fputcsv adds a line ending on the last element

I have a basic PHP script that creates a csv file from an array. Here is an example of the code:
$array = [
[1,2,3],
[4,5,6]
];
$handle = fopen('test.csv', 'w');
foreach($array as $v)
fputcsv($handle, $v);
fclose($handle);
The resulting file always has a blank line at the end of the file, because fputcsv doesn't know that this is the last line. Any (simple) ideas on how to prevent this?
EDIT:
The original question is now irrelevant (to me, but maybe someone will need to do this). fputcsv is supposed to add a new line, even at the end of the document, and this is the expected behavior of all csv files.
I marked the answer that solves the original question, even though it isn't relevant to me anymore.
So in my context, I needed to check if the last line (or any line) of the array is NULL (otherwise PHP will through up a Warning that fputcsv's 2nd parameter is null). Here is my updated script if anyone is interested:
$array = [
[1,2,3],
[4,5,6]
];
$handle = fopen('test.csv', 'w');
foreach($array as $v)
if($v != NULL)
fputcsv($handle, $v);
fclose($handle);
I found this solution on another question: https://stackoverflow.com/a/8354413/1564018
$stat = fstat($handle);
ftruncate($handle, $stat['size']-1);
I added these two lines after fputcsv() and they removed the last new line character, removing the blank line at the end of the file.
Add exit(); at the end, after fclose(handle);
Like #Barmar says, all lines have a line ending, let's say \n. What you see as a blank line at the end of the file is your editor doing that. A truly blank line is two line-ending characters in succession. (\n\n for example)
Imagine you have a blank file:
(EOF)
If you fputcsv this: array(0,"hello",3323) you get
(0,hello,3323\nEOF)
given PHP docs:
fputcsv() formats a line (passed as a fields array) as CSV and write it (terminated by a newline) to the specified file handle.
A blank line in your editor is expected then. But in the file there's no such thing.
fputcsv adds a new line after each line, that's how it works. From the docs:
fputcsv() formats a line (passed as a fields array) as CSV and write it (terminated by a newline)
A new line at the end of a file is not an error, or something you need to worry about. Don't try to remove it, just leave it.
In the comments, you mention you got an error:
Warning: fputcsv() expects parameter 2 to be array, boolean given
This is probably because you are not using fgetcsv correctly. It returns FALSE when it hits the end of the file (the new line). The docs show you how to use it correctly:
while (($data = fgetcsv($handle)) !== FALSE) {
}

Categories