Is it possible to load a single row from a CSV file? - php

Using PHP, is it possible to load just a single record / row from a CSV file?
In other words, I would like to treat the file as an array, but don't want to load the entire file into memory.
I know this is really what a database is for, but I am just looking for a down and dirty solution to use during development.
Edit: To clarify, I know exactly which row contains the info I am looking for.
I would just like to know if there is a way to get it without having to read the entire file into memory.

As I understand you are looking for a row with certain data. Therefore you could probably implement the following logic:
(1) scan file for the given data (ex. value which is in the row that you are trying to find),
(2) load only this line of file,
(3) perform your operations on that line.

fgetcsv() operates over a file resource handle, so if you want you can obtain the position of the line you can fseek() the resource to that position and use fgetcsv() normally.

If you don't know which line you are looking for until after you have read the row, your best bet is reading the record until you find the record by testing the array that is returned.
$fp = fopen('data.csv', 'r');
while(false !== ($data = fgetcsv($fp, 0, ','))) {
if ($data['field'] === 'somevalue') {
echo 'Hurray';
break;
}
}
If you are looking to read a specific line, use the splfile object and seek to the record number. This will return a string that you must convert to an array
$file = new SplFileObject('data.csv');
$file->seek(2);
$record = $file->current();
$data = explode(",", $record);

Related

Read in text file in binary search with PHP without using ram memory

I need to make script that reads a file delimite by pipes "|" in with binary search without using memory ram. How can I do it?
I tried:
$handle = fopen("myfile.txt", "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
// while reads line make binary search
}
fclose($handle);
} else {
// error opening the file.
}
myfile.txt
Name|Title|Andrew|TheBook1|July|TheChest|Carol|OneTime
Since its homework, I ll give you some tips/steps, you figure out how to implement them :)
The binary search algorithm divides the the search into blocks. On each step, it chops the block which contains the element into half. That's why initially it aproximates very fast.
For that matter you need your data ordered alphabetically. The exercise says you have to implement a binary search without using memory. Doesn't say you can't use memory to order your data. So explode that string by "|", order it alphabetically and implode it again. There you have you ordered string.
For the actual algorithm you can't use memory, so you'll have to work with the filesystem only.
You need to know where the block your're searching in starts and finnishes.
I don't know if you are allowed to use variables in memory. If not, you'll have to write your variables to a file as well.
In that case, write functions like getBlockStart(), getBlockEnd(), setBlockStart, setBlockEnd() which read/write the values from a file.
Start the algorithm with blockStart = <first element>, blockEnd = <lastELement>
Chop in 2 parts and look in which part your element is based on the alphabetical order.
To check out the 10th, just read 10 elements of the file. That way you reach it.
Repeat until you find the element you looking for.
You can use stream_get_line to use pipelines as delimiters.
while (($name = stream_get_line($handle, 0, '|')) !== false) {
// if ($name == 'Carol') { ...
}

Get first row of csv file in laravel

I want to ask how can I get the first row (the column names) in laravel?
For now I load my file from storage.
I have tried $contents[0]; but it did not work.
public function csvread(Request $request) {
$contents = Storage::disk('public')->get('asdf.csv');
}
Thanks!
I don't know Laravel so I cannot comment specifically on the functionality of Storage. However, I had a look at the documentation, which states the following:
The get method may be used to retrieve the contents of a given file. The raw string contents of the file will be returned by the method
So, assuming the call you made successfully found and read a file, $contents is a string - and dereferencing $contents[0] is just going to return the first character of the string. Not what you want, clearly!
I concur wth #JonStirling in the question comments and try to parse the csv directly with fgetcsv(). Or, if you want to be more object-based you could use SplFileObject() which can read and iterate over CSV files, given the appropriate flags.
Here's a copy of example #2 from the PHP docs:
$file = new SplFileObject("animals.csv");
$file->setFlags(SplFileObject::READ_CSV);
foreach ($file as $row) {
list($animal, $class, $legs) = $row;
printf("A %s is a %s with %d legs\n", $animal, $class, $legs);
}
You'll need the orignal filepath to pass to SplFileObject() too of course - this answer should be useful
Finally, if your CSV has empty lines, you might have to add additional flags to SplFileObject - namely SplFileObject::SKIP_EMPTY and SplFileObject::READ_AHEAD
You may also opt to use a pre-existing package; e.g: http://csv.thephpleague.com/
Hope this helps! :)

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 - read from flatfile, remove line and write back to flat file

Would appreciate some assistance
i have a txt file witht he following contents:
1234|dog|apartment|two
1234|cat|apartment|one
1234|dog|house|two
1234|dog|apartment|three
I want to delete the entry where the animal is "dog" living in an "house"
<?php
if (isset($_POST['delete_entry]))
{
//identifies the file
$file = "db.txt";
//opens the file to read
#$fpo = fopen($file, 'r');
//while we have not reached the end of the file
while(!feof($fpo))
{
//read each line of the file into an array called animal
$animal[] = fgets($fpo);
}
//close the file
fclose($fpo);
//iterate through the array
foreach ($animal as $a)
{
if the string contains dog and apartment
if ((stripos ($a, 'dog']))&&(stripos ($a, 'house')))
{
//dont do anything
}
else
{
//otherwise print out the string
echo $a.'<br/>';
}
}
}
?>
This successfully prints out the array without the entry where 'dog' and 'house' appears.
I need to write this back to the flat file though, but running into difficulties.
I have tried a variety of options include writting back to the file immediately when each entry is found.
Warning: feof() expects parameter 1 to be resource, boolean given in
Warning: fwrite(): 9 is not a valid stream resource in
Warning: fclose(): 9 is not a valid stream resource in
These are amongst the errors i have encountered. Now from my understanding of arrays,
- when i go through this array called animal,
- it checks index [0] for the two conditions and
- if the entry is not found, it assigns to to $a.
- It then goes through the array starting at index [1],
- and so forth.
Each time the new value is assigned to $a.
I thought that printing it to file each time it appears might work, but this is where i get the fwrite and fclose errors above, and no idea how to resolve this (yet).
I still have to do the bit where i need to replace 'apartment' with house, for one specifically selected entry, but will get there once I have sorted out the "delete"
I dont need code, maybe just a logic flow that might assist me.
Thanks
To save some time, you could store your data in array only if it passes your validation rules when it's being read from file, and after reading the end of file, you'd have array ready for writing it back to file.
How about this for steps:
Read the file.
Store File contents in array.
Remove item from array.
Overwrite the file with new contents.
What you can do is opening the source file in read mode and a temporary file in write mode. As you read content from the "in" file, you write lines to the "out" file. When the "in" file is processed and closed, you rename "out" to "in". This way you need to worry less about memory constraints.
When processing each line, it's better if you split on '|', so you know that the second element contains an animal name and the third element contains a housing name. Who knows if a cat is living in a doghouse.
<?php
$fileName = 'db.txt';
$data = #file($fileName);
$id = 0;
$animal = "";
$type = "";
$number = 0;
$excludeAnimal = array("dog");
$excludeHouseType = array("house");
foreach($data as $row) {
list($id,$animal,$type,$number) = explode("|",$row);
if(in_array($animal,$excludeAnimal) && in_array($type,$excludeHouseType))
continue
/* ... code ... */
}
?>
Although this doesn't answer your original question, I'd like to share what I've come up with.
I'm pretty sure this will do your entire script in three lines:
$file = file_get_contents( 'db.txt');
$result = preg_replace('/^\d+\|dog\|house\|\w+$/m', '', $file);
file_put_contents( 'db.txt', $result);
It uses a regex to replace the lines with dog|house, then writes the file back.
Read and dump all data until the one you want deleted into $array_1.
Read and dump rest of file into $array_2.
Concatenate 2 arrays in a $newarray, rewrite to original flatfile.
Simple!

Read CSV from end to beginning in PHP

I am using PHP to expose vehicle GPS data from a CSV file. This data is captured at least every 30 seconds for over 70 vehicles and includes 19 columns of data. This produces several thousand rows of data and file sizes around 614kb. New data is appended to end of the file. I need to pull out the last row of data for each vehicle, which should represent the most the recent status. I am able to pull out one row for each unit, however since the CSV file is in chronological order I am pulling out the oldest data in the file instead of the newest. Is it possible to read the CSV from the end to the beginning? I have seen some solutions, however they typically involve loading the entire file into memory and then reversing it, this sounds very inefficient. Do I have any other options? Thank you for any advice you can offer.
EDIT: I am using this data to map real-time locations on-the-fly. The data is only provided to me in CSV format, so I think importing into a DB is out of the question.
With fseek you can set the pointer to the end of the file and offset it negative to read a file backwards.
If you must use csv files instead of a database, then perhaps you could read the file line-by-line. This will prevent more than the last line being stored in memory (thanks to the garbage collector).
$handle = #fopen("/path/to/yourfile.csv", "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
// old values of $last are garbage collected after re-assignment
$last = $line;
// you can perform optional computations on past data here if desired
}
if (!feof($handle)) {
echo "Error: unexpected fgets() fail\n";
}
fclose($handle);
// $last will now contain the last line of the file.
// You may now do whatever with it
}
edit: I did not see the fseek() post. If all you need is the last line, then that is the way to go.

Categories