18

In PHP if you write to a file it will write end of that existing file.

How do we prepend a file to write in the beginning of that file?

I have tried rewind($handle) function but seems overwriting if current content is larger than existing.

Any Ideas?

alex
  • 479,566
  • 201
  • 878
  • 984
mathew
  • 1,179
  • 2
  • 13
  • 24
  • 3
    Non-pretty way would be to read file contents, prepend whatever you have, and rewrite the entire file. Not sure if there's another way. If you're making a small modification to a huge file, then this isn't exactly "light", but if you're working on a small 100char file, this'll be fine. – Warty Jul 26 '10 at 04:50
  • You may want to do this with UNIX tools, if that's a possibility: http://stackoverflow.com/questions/54365/prepend-to-a-file-one-liner-shell – deceze Jul 26 '10 at 05:04

6 Answers6

34
$prepend = 'prepend me please';

$file = '/path/to/file';

$fileContents = file_get_contents($file);

file_put_contents($file, $prepend . $fileContents);
alex
  • 479,566
  • 201
  • 878
  • 984
  • Alex there is a correction $fileContents = file_get_contents($file); – mathew Jul 26 '10 at 05:05
  • Alex one more question..if this is a large file then read/write may take more time right?? – mathew Jul 26 '10 at 05:08
  • If the file is huge you could always use streams (ie. fread and fwrite) and a temporary file. – GWW Jul 26 '10 at 05:12
  • 1
    @matthew It may. The [docs](http://www.php.net/manual/en/function.file-put-contents.php) say calling `file_put_contents()` is identical to using `fopen()` and similar. If performance becomes a problem, you can always look into Deceze's suggestion (in the comments to your question). – alex Jul 26 '10 at 05:18
17

The file_get_contents solution is inefficient for large files. This solution may take longer, depending on the amount of data that needs to be prepended (more is actually better), but it won't eat up memory.

<?php

$cache_new = "Prepend this"; // this gets prepended
$file = "file.dat"; // the file to which $cache_new gets prepended

$handle = fopen($file, "r+");
$len = strlen($cache_new);
$final_len = filesize($file) + $len;
$cache_old = fread($handle, $len);
rewind($handle);
$i = 1;
while (ftell($handle) < $final_len) {
  fwrite($handle, $cache_new);
  $cache_new = $cache_old;
  $cache_old = fread($handle, $len);
  fseek($handle, $i * $len);
  $i++;
}
?>
ashastral
  • 2,818
  • 1
  • 21
  • 32
  • 2
    `file_get_contents()` [docs](http://php.net/manual/en/function.file-get-contents.php) does say this: "...is the preferred way to read the contents of a file into a string. It will use memory mapping techniques if supported by your OS to enhance performance." – alex Jul 26 '10 at 05:45
  • 4
    @alex It still means it'll read the whole thing into memory all at once. Fraxtil's method is using very little memory, but a lot of steps. It depends on the circumstances which one is more efficient... – deceze Jul 26 '10 at 05:49
  • Great thanks!! it works I was little bit worried about file_get_contents – mathew Jul 26 '10 at 06:21
  • 1
    If i interpret this correctly, this indeed does a file copy with a prepend. But the steps are heavily dependent on the size of the prepend string. Easiest example: a prepend string of size 1 (ie: 'X') would take 1024 steps on a 1kb file. This is not quite acceptable for smaller strings. Also there is a missed chance for a `do { .. } while();`construct :) – scones Apr 16 '18 at 09:00
  • Interesting solution to append data with minimal disk memory overhead but as @scones wrote, this is can be highly inefficient depending on the situation. A better way would be probably to use a fixed width $cache_new with added bytes from the original file, if it is too long, and then use this fixed length for copy operations. – StanE Jun 29 '22 at 19:47
5
$filename  = "log.txt";
$file_to_read = @fopen($filename, "r");
$old_text = @fread($file_to_read, 1024); // max 1024
@fclose(file_to_read);
$file_to_write = fopen($filename, "w");
fwrite($file_to_write, "new text".$old_text);
Nicolas Defranoux
  • 2,646
  • 1
  • 10
  • 13
misima
  • 421
  • 5
  • 17
2

Another (rough) suggestion:

$tempFile = tempnam('/tmp/dir');
$fhandle = fopen($tempFile, 'w');
fwrite($fhandle, 'string to prepend');

$oldFhandle = fopen('/path/to/file', 'r');
while (($buffer = fread($oldFhandle, 10000)) !== false) {
    fwrite($fhandle, $buffer);
}

fclose($fhandle);
fclose($oldFhandle);

rename($tempFile, '/path/to/file');

This has the drawback of using a temporary file, but is otherwise pretty efficient.

deceze
  • 510,633
  • 85
  • 743
  • 889
-2

When using fopen() you can set the mode to set the pointer (ie. the begginng or end.

$afile = fopen("file.txt", "r+");

'r' Open for reading only; place the file pointer at the beginning of the file.

'r+' Open for reading and writing; place the file pointer at the beginning of the file.

Community
  • 1
  • 1
dockeryZ
  • 3,981
  • 1
  • 20
  • 28
-5
            $file = fopen('filepath.txt', 'r+') or die('Error');
            $txt = "/n".$string;
            fwrite($file, $txt);
            fclose($file);

This will add a blank line in the text file, so next time you write to it you replace the blank line. with a blank line and your string.

This is the only and best trick.

Dillon Burnett
  • 473
  • 4
  • 11
  • 2
    Firstly this isn't prepending, it's overwriting. More importantly, /n inserts a new line character (there's no such thing as a blank line) so the most you could overwrite would be 1 character. This is such a bad answer I can't tell if you're trolling. – Michael Whinfrey Apr 29 '19 at 22:17