Delete a specific line in a TXT file - php

I have a .txt file with millions of lines of text
The code below Delete a specific line (.com domains) in a .txt file. But large files can not do :(
<?php
$fname = "test.txt";
$lines = file($fname);
foreach($lines as $line) if(!strstr($line, ".com")) $out .= $line;
$f = fopen($fname, "w");
fwrite($f, $out);
fclose($f);
?>
I want to remove certain lines and put them in another file
For example, the list of domain names of sites. cut the .com domain and paste it in another file...

Here's an approach using http://php.net/manual/en/class.splfileobject.php and working with a temporary file.
$fileName = 'whatever.txt';
$linesToDelete = array( 3, 5 );
// Working File
$file = new SplFileObject( $fileName, 'a+' );
$file->flock( LOCK_EX );
// Temp File
$temp = new SplTempFileObject( 0 );
$temp->flock( LOCK_EX );
// Wite the temp file without the lines
foreach( $file as $key => $line )
{
if( in_array( $key + 1, $linesToDelete ) === false )
{
$temp->fwrite( $line );
}
}
// Write Back to the main file
$file->ftruncate(0);
foreach( $temp as $line )
{
$file->fwrite( $line );
}
$file->flock( LOCK_UN );
$temp->flock( LOCK_UN );
This may be slow though, but a 40 meg file with 140000 lines takes 2.3 seconds on my windows xampp setup. This could be sped up by writing to a temp file and doing a file move, but I didn't want to step on file permissions in your environment.
Edit: Solution using Rename/Move instead of second write
$fileName = __DIR__ . DIRECTORY_SEPARATOR . 'whatever.txt';
$linesToDelete = array( 3, 5 );
// Working File
$file = new SplFileObject( $fileName, 'a+' );
$file->flock( LOCK_EX );
// Temp File
$tempFileName = tempnam( sys_get_temp_dir(), rand() );
$temp = new SplFileObject( $tempFileName,'w+');
$temp->flock( LOCK_EX );
// Write the temp file without the lines
foreach( $file as $key => $line )
{
if( in_array( $key + 1, $linesToDelete ) === false )
{
$temp->fwrite( $line );
}
}
// File Rename
$file->flock( LOCK_UN );
$temp->flock( LOCK_UN );
unset( $file, $temp ); // Kill the SPL objects relasing further locks
unlink( $fileName );
rename( $tempFileName, $fileName );

It could be because of the large size of the file that its taking too much of space.
When you do file('test.txt'), it reads the entire file into an array.
Instead, you can try using Generators.
GeneratorsExample.php
<?php
class GeneratorsExample {
function file_lines($filename) {
$file = fopen($filename, 'r');
while (($line = fgets($file)) !== false) {
yield $line;
}
fclose($file);
}
function copyFile($srcFile, $destFile) {
foreach ($this->file_lines($srcFile) as $line) {
if(!strstr($line, ".com")) {
$f = fopen($destFile, "a");
fwrite($f, $line);
fclose($f);
}
}
}
}
callingFile.php
<?php
include('GeneratorsExample.php');
$ob = new GeneratorsExample();
$ob->copyFile('file1.txt', 'file2.txt')

While you could use tens of lines of PHP code, one line of shell code will do.
$ grep Bar.com stuff.txt > stuff2.txt
or as PHP
system ("grep Bar.com stuff.txt > stuff2.txt");

Related

I want to delete a line in txt file

I use PHP to read a txt file,I read the first line, it is ok.
but when I want to delete the first line.
it fails.....
I can do this code in localhost,but when I boot in server
it fail.....I dont know why...
this is my code:
<?php
$handle = fopen('newfile.txt', "r");
$contents = '';
if ($handle) {
while (!feof($handle)) {
$contents = fgets($handle, 10);
echo $contents;
$filename = 'newfile.txt';
$content = file_get_contents('newfile.txt');
$content = str_replace($contents, '', $content);
file_put_contents('newfile.txt', $content);
exit;
}
fclose($handle);
}
?>
An alternative to the complicated code above ( which I did not check btw ) might be
$file='newfile.txt';
$lines=file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
array_shift( $lines );
file_put_contents( $file, implode( PHP_EOL, $lines ) );
If it is important to display the line that is being removed then:
$file='newfile.txt';
$lines=file( $file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES );
$sentence = array_shift( $lines );
echo $sentence;
file_put_contents( $file, implode( PHP_EOL, $lines ) );

So say I have a directory like this

Folder
File1.txt
File2.txt
File3.txt
File4.txt
File5.txt
File6.txt
File7.txt
File8.txt
File9.txt
But whenever I add another file it looks like this
File1.txt
File10.txt //NEW FILE
File2.txt
File3.txt
File4.txt
File5.txt
File6.txt
File7.txt
File8.txt
File9.txt
And mabey I add another file
File1.txt
File10.txt //NEW FILE
File11.txt //NEWER FILE
File2.txt
File3.txt
File4.txt
File5.txt
File6.txt
File7.txt
File8.txt
File9.txt
And as you can guess when I include all these files in one PHP file
It messes up...
Say that file1.txt has the contents :1
File10.txt has the contents :10
File2.txt has the contents :2
File3.txt has the contents :3
And so on
When I include this the order on the page appears as this
1
10
2
3
4
5
And so on
So how do I get the files to appear in number order???
Here is the code I'm working with
<?php
// Add correct path to your countlog.txt file.
$path = 'ChatNumbers.txt';
// Opens countlog.txt to read the number of hits.
$file = fopen( $path, 'r' );
$count = fgets( $file, 1000 );
fclose( $file );
// Update the count
$count = abs( intval( $count ) ) + "1";
// Opens countlog.txt to change new hit number.
$file = fopen( $path, 'w' );
fwrite( $file, $count);
fclose( $file );
$ab = 'Chat_';
$cn = "$count";
$rp = '.html';
$fr = "$ab$cn$rp";
$path = "Chats/$fr";
if (isset($_POST['field1'])) {
$fh = fopen($path,"a+");
$string = $_POST['field1'].'<p></p>';
fwrite($fh,$string); // Write information to the file
fclose($fh); // Close the file
}
?>
And This is how I am currently including my files
<php
foreach (glob("chat/Chats/*.html") as $filename)
{
include $filename;
}
?>
Not the best way to go about all of this I'm sure, but to answer the question, you need to sort (naturally):
$files = glob("chat/Chats/*.html");
natsort($files);
foreach ($files as $filename)
{
include $filename;
}

How can I create an array by parsing a large file? [duplicate]

I want to read a file line by line, but without completely loading it in memory.
My file is too large to open in memory, and if try to do so I always get out of memory errors.
The file size is 1 GB.
You can use the fgets() function to read the file line by line:
$handle = fopen("inputfile.txt", "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
// process the line read.
}
fclose($handle);
}
if ($file = fopen("file.txt", "r")) {
while(!feof($file)) {
$line = fgets($file);
# do same stuff with the $line
}
fclose($file);
}
You can use an object oriented interface class for a file - SplFileObject http://php.net/manual/en/splfileobject.fgets.php (PHP 5 >= 5.1.0)
<?php
$file = new SplFileObject("file.txt");
// Loop until we reach the end of the file.
while (!$file->eof()) {
// Echo one line from the file.
echo $file->fgets();
}
// Unset the file to call __destruct(), closing the file handle.
$file = null;
If you want to use foreach instead of while when opening a big file, you probably want to encapsulate the while loop inside a Generator to avoid loading the whole file into memory:
/**
* #return Generator
*/
$fileData = function() {
$file = fopen(__DIR__ . '/file.txt', 'r');
if (!$file) {
return; // die() is a bad practice, better to use return
}
while (($line = fgets($file)) !== false) {
yield $line;
}
fclose($file);
};
Use it like this:
foreach ($fileData() as $line) {
// $line contains current line
}
This way you can process individual file lines inside the foreach().
Note: Generators require >= PHP 5.5
There is a file() function that returns an array of the lines contained in the file.
foreach(file('myfile.txt') as $line) {
echo $line. "\n";
}
The obvious answer wasn't there in all the responses.
PHP has a neat streaming delimiter parser available made for exactly that purpose.
$fp = fopen("/path/to/the/file", "r");
while (($line = stream_get_line($fp, 1024 * 1024, "\n")) !== false) {
echo $line;
}
fclose($fp);
Use buffering techniques to read the file.
$filename = "test.txt";
$source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
while (!feof($source_file)) {
$buffer = fread($source_file, 4096); // use a buffer of 4KB
$buffer = str_replace($old,$new,$buffer);
///
}
foreach (new SplFileObject(__FILE__) as $line) {
echo $line;
}
One of the popular solutions to this question will have issues with the new line character. It can be fixed pretty easy with a simple str_replace.
$handle = fopen("some_file.txt", "r");
if ($handle) {
while (($line = fgets($handle)) !== false) {
$line = str_replace("\n", "", $line);
}
fclose($handle);
}
This how I manage with very big file (tested with up to 100G). And it's faster than fgets()
$block =1024*1024;//1MB or counld be any higher than HDD block_size*2
if ($fh = fopen("file.txt", "r")) {
$left='';
while (!feof($fh)) {// read the file
$temp = fread($fh, $block);
$fgetslines = explode("\n",$temp);
$fgetslines[0]=$left.$fgetslines[0];
if(!feof($fh) )$left = array_pop($lines);
foreach ($fgetslines as $k => $line) {
//do smth with $line
}
}
}
fclose($fh);
Be careful with the 'while(!feof ... fgets()' stuff, fgets can get an error (returnfing false) and loop forever without reaching the end of file. codaddict was closest to being correct but when your 'while fgets' loop ends, check feof; if not true, then you had an error.
SplFileObject is useful when it comes to dealing with large files.
function parse_file($filename)
{
try {
$file = new SplFileObject($filename);
} catch (LogicException $exception) {
die('SplFileObject : '.$exception->getMessage());
}
while ($file->valid()) {
$line = $file->fgets();
//do something with $line
}
//don't forget to free the file handle.
$file = null;
}
<?php
echo '<meta charset="utf-8">';
$k= 1;
$f= 1;
$fp = fopen("texttranslate.txt", "r");
while(!feof($fp)) {
$contents = '';
for($i=1;$i<=1500;$i++){
echo $k.' -- '. fgets($fp) .'<br>';$k++;
$contents .= fgets($fp);
}
echo '<hr>';
file_put_contents('Split/new_file_'.$f.'.txt', $contents);$f++;
}
?>
Function to Read with array return
function read_file($filename = ''){
$buffer = array();
$source_file = fopen( $filename, "r" ) or die("Couldn't open $filename");
while (!feof($source_file)) {
$buffer[] = fread($source_file, 4096); // use a buffer of 4KB
}
return $buffer;
}

How to unzip a zip file that has another zip file inside using PHP

I have a file xyz.zip and in this file there are two more files test.xml and another abc.zip file that contains test2.xml. When i use this code it only extract xyz.zip file. But i also need to extract abc.zip.
xyz.zip
- test.xml
- abc.zip
- test2.xml
<?php
$filename = "xzy.zip";
$zip = new ZipArchive;
if ($zip->open($filename) === TRUE) {
$zip->extractTo('./');
$zip->close();
echo 'Success!';
}
else {
echo 'Error!';
}
?>
Can somebody please tell me how can i extract everything in zip files? Even abc.zip. So that the output will be in a folder (test.xml and test2.xml).
Thanks
this might help you.
This function will flatten a zip file using the ZipArchive class.
It will extract all the files in the zip and store them in a single destination directory. That is, no sub-directories will be created.
<?php
// dest shouldn't have a trailing slash
function zip_flatten ( $zipfile, $dest='.' )
{
$zip = new ZipArchive;
if ( $zip->open( $zipfile ) )
{
for ( $i=0; $i < $zip->numFiles; $i++ )
{
$entry = $zip->getNameIndex($i);
if ( substr( $entry, -1 ) == '/' ) continue; // skip directories
$fp = $zip->getStream( $entry );
$ofp = fopen( $dest.'/'.basename($entry), 'w' );
if ( ! $fp )
throw new Exception('Unable to extract the file.');
while ( ! feof( $fp ) )
fwrite( $ofp, fread($fp, 8192) );
fclose($fp);
fclose($ofp);
}
$zip->close();
}
else
return false;
return $zip;
}
/*
How to use:
zip_flatten( 'test.zip', 'my/path' );
*/
?>
You should use a recursive function that check all the extracted files and if it finds out one of them is a zip, then call itself again.
function scanDir($path) {
$files = scandir($path);
foreach($files as $file) {
if (substr($file, -4)=='.zip')
unzipRecursive($path, $file);
elseif (isdir($path.'/'.$file))
scanDir($path.'/'.$file);
}
}
function unzipRecursive($absolutePath, $filename) {
$zip = new ZipArchive;
$newfolder = $absolutePath.'/'.substr($file, 0, -4);
if ($zip->open($filename) === TRUE) {
$zip->extractTo($newfolder);
$zip->close();
//Scan the directory
scanDir($newfolder)
} else {
echo 'Error unzipping '.$absolutePath.'/'.$filename;
}
}
I didn't try the code but it's only to debug a little I guess

How can I read 30MB text file using php script?

Hi I do have a text file with size of upto 30MB I would like to read this file using PHP loop script
$lines = file('data.txt');
//loop through each line
foreach ($lines as $line) { \\some function }
Is there any way? I want open it for reading php doesnt allow me to open a 30MB file.
You could read it line by line like this:
$file = fopen("data.txt", "r") or exit("Unable to open file!");
while(!feof($file)) {
// do what you need to do with it - just echoing it out for this example
echo fgets($file). "<br />";
}
fclose($file);
Read line by line using:
$handle = fopen ( "data.txt", "r" );
while ( ( $buffer = fgets ( $handle, 4096 ) ) !== false ) {
// your function on line;
}
If it is suitable for you to read the file piece-by-piece you can try something like this
$fd = fopen("fileName", "r");
while (!feof($fd)) {
$buffer = fread($fd, 16384); //You can change the size of the buffer according to the memory you can youse
//Process here the buffer, piece by piece
}
fclose($fd);

Categories