PHP如何在文件开头写入内容?

46

我正在制作这个程序,我想知道如何将数据写入文件开头而不是结尾。 "a"/追加 只能写入到结尾,如何让它写入到开头?因为 "r+" 可以做到,但会覆盖之前的数据。

$datab = fopen('database.txt', "r+");

这是我的整个文件:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>Facebook v0.1</title>
        <style type="text/css">
            #bod{
                margin:0 auto;
                width:800px;
                border:solid 2px black;
            }
        </style>
    </head>

    <body>
        <div id="bod">
            <?php
                $fname = $_REQUEST['fname'];
                $lname = $_REQUEST['lname'];
                $comment = $_REQUEST['comment'];
                $datab = $_REQUEST['datab'];
                $gfile = $_REQUEST['gfile'];

                print <<<form
                <table border="2" style="margin:0 auto;">
                    <td>
                        <form method="post"  action="">
                              First Name :
                              <input type ="text"
                                         name="fname"
                                         value="">
                              <br>

                              Last Name :
                                <input type ="text"
                                         name="lname"
                                         value="">
                              <br>

                              Comment :
                              <input type ="text"
                                         name="comment"
                                         value="">
                              <br>
                              <input type ="submit" value="Submit">
                        </form>
                    </td>
                </table>
                form;
                if((!empty($fname)) && (!empty($lname)) && (!empty($comment))){
                    $form = <<<come

                    <table border='2' width='300px' style="margin:0 auto;">
                        <tr>
                            <td>
                                <span style="color:blue; font-weight:bold;">
                                $fname $lname :
                                </span>

                                $comment
                            </td>
                        </tr>
                    </table>
                    come;

                    $datab = fopen('database.txt', "r+");
                    fputs($datab, $form);
                    fclose($datab);

                }else if((empty($fname)) && (empty($lname)) && (empty($comment))){
                    print" please input data";
                } // end table

                $datab = fopen('database.txt', "r");

                while (!feof($datab)){
                    $gfile = fgets($datab);
                    print "$gfile";
                }// end of while
            ?>
        </div>
    </body>
</html>
10个回答

68

简单明了:

<?php
$file_data = "Stuff you want to add\n";
$file_data .= file_get_contents('database.txt');
file_put_contents('database.txt', $file_data);
?>

3
我认为在文件开头插入数据没有更好的方法。你必须无论如何移动文件中当前包含的所有数据。对于较大的文件,您可能需要逐部分读取文件以适应内存。 - Kamil Szot
使用fopen的“c”模式怎么样?这不会写入文件的开头吗? - SSH This
1
@SSHThis 是的,它可以重写任何阻碍它的东西。 - jave.web
使用 FILE_APPEND 避免覆盖。 - Fronto
这个应该使用多大的文件?如果有多个进程同时写入文件怎么办?使用fopen()和flock()调用可以避免这种情况发生吗? - Richard
@Fronto,您能详细解释一下FILE_APPEND吗?我在PHP手册中找不到相关内容。谢谢。 - snoski

47

如果您不想将整个文件的内容加载到变量中,可以使用PHP的特性:

function prepend($string, $orig_filename) {
  $context = stream_context_create();
  $orig_file = fopen($orig_filename, 'r', 1, $context);

  $temp_filename = tempnam(sys_get_temp_dir(), 'php_prepend_');
  file_put_contents($temp_filename, $string);
  file_put_contents($temp_filename, $orig_file, FILE_APPEND);

  fclose($orig_file);
  unlink($orig_filename);
  rename($temp_filename, $orig_filename);
}

这段代码的作用是将要添加在文件开头的字符串写入一个临时文件,然后使用流将原始文件的内容写入临时文件的末尾(而不是将整个文件复制到变量中),最后删除原始文件并将临时文件重命名以替换它。

注意:此代码最初基于 Chao Xu 的一篇已失效的博客文章。该代码已经分叉,但可以通过 Wayback Machine 查看原始文章


2
谢谢!这个很好用,但只有当文件存在时才有效(我遇到过文件可能丢失的情况。解决起来非常简单:if (!file_exsists($filename) [...] )。 - qualbeen
1
PHP提供了tempnam()函数来生成唯一的文件名。而md5()函数在生成文件名时有极小的可能性与已存在的文件发生冲突。请参考http://php.net/manual/en/function.tempnam.php。 - Vincent Nikkelen
2
我使用了这个解决方案,但是将$tmpname定义为$tmpname = tempnam(sys_get_temp_dir(), 'tmp_prepend_');,这样它就会使用系统文件夹来存储临时文件,并使用标准的PHP方法来生成临时文件名,从而减少了文件系统权限错误的可能性。 - dubrox
@dubrox VincentNikkelen 谢谢。我已经更新了代码。 - Jordan Running
如果您在目标文件上遇到权限错误(例如Apache无法读取),请尝试在与目标文件相同的文件夹中创建临时文件,而不是在系统文件夹中创建。这对我有用。 - marlar

5

我认为您可以先读取文件内容并将其保存在临时变量中,现在在文件开头插入新数据,然后再附加临时变量的内容。

$file = file_get_contents($filename);
$content = '您的内容' . $file;
file_put_contents($filename, $content);  

4
  1. Open a file in w+ mode not a+ mode.
  2. Get the length of text to add ($chunkLength)
  3. set a file cursor to the beginning of the file if needed
  4. read $chunkLength bytes from the file
  5. return the cursor to the $chunkLength * $i;
  6. write $prepend
  7. set $prepend a value from step 4
  8. do these steps, while EOF

    $handler = fopen('1.txt', 'w+');//1
    rewind($handler);//3
    $prepend = "I would like to add this text to the beginning of this file";
    $chunkLength = strlen($prepend);//2
    $i = 0;
    do{
        $readData = fread($handler, $chunkLength);//4
        fseek($handler, $i * $chunkLength);//5
        fwrite($handler, $prepend);//6
    
        $prepend = $readData;//7
        $i++;
    }while ($readData);//8
    
    fclose($handler);
    

在这种情况下,$i * $chunkLength 不总是为0吗? - Christian Rauchenwald

3
您可以使用以下代码在文件开头和结尾添加文本。
$myFile = "test.csv";<br>
$context = stream_context_create();<br>
  $fp = fopen($myFile, 'r', 1, $context);<br>
  $tmpname = md5("kumar");<br>

//this will append text at the beginning of the file<br><br>
  file_put_contents($tmpname, "kumar");<br>
  file_put_contents($tmpname, $fp, FILE_APPEND);<br>
  fclose($fp);<br>
  unlink($myFile);<br>
  rename($tmpname, $myFile);<br><br>
  //this will append text at the end of the file<br>
  file_put_contents($myFile, "ajay", FILE_APPEND);

2
您可以使用 fseek 来改变笔记中的指针。
需要注意的是,如果您使用 fwrite,它将擦除当前内容。因此,您基本上需要读取整个文件,使用 fseek,写入新内容,再写入文件的旧数据。
$file_data = file_get_contents('database.txt')
$fp = fopen('database.txt', 'a');
fseek($fp,0);
fwrite($fp, 'new content');
fwrite($fp, $file_data);
fclose($fp);

如果您的文件非常大,而且不想使用太多内存,您可以尝试使用两个文件的方法,例如:
$fp_source = fopen('database.txt', 'r');
$fp_dest = fopen('database_temp.txt', 'w'); // better to generate a real temp filename
fwrite($fp_dest, 'new content');
while (!feof($fp_source)) {
    $contents .= fread($fp_source, 8192);
    fwrite($fp_dest, $contents);
}
fclose($fp_source);
fclose($fp_dest);
unlink('database.txt');
rename('database_temp.txt','database.txt');

在我看来,Ben的解决方案更加直接。最后一点:我不知道你在database.txt中存储了什么,但使用数据库服务器可能更容易实现相同的结果。

2

一行:

file_put_contents($file, $data."\r\n".file_get_contents($file));

或者:

file_put_contents($file, $data."\r\n --- SPLIT --- \r\n".file_get_contents($file));

1

这段代码会记住文件开头的数据,以保护它们不被覆盖。接下来,它会逐块地重写文件中所有现有的数据。

$data = "new stuff to insert at the beggining of the file";
$buffer_size = 10000;

$f = fopen("database.txt", "r+");
$old_data_size = strlen($data);
$old_data = fread($f, $old_data_size);
while($old_data_size > 0) {
  fseek($f, SEEK_CUR, -$old_data_size);
  fwrite($f, $data);
  $data = $old_data;
  $old_data = fread($f, $buffer_size);
  $old_data_size = strlen($data);
}
fclose($f);

1

像你想的那样,没有办法写入文件的开头。我猜这是由于操作系统和硬盘如何看待文件的原因。它有一个固定的开始和扩展的结尾。如果你想在中间或开头添加一些东西,就需要进行一些滑动。如果它是一个小文件,只需读取所有内容并进行操作,然后再写回去。但如果不是,而且如果你总是在开头添加,只需反转行顺序,将结尾视为开头...


0

file_get_contents()file_put_contents() 使用的内存比使用 fopen()fwrite()fclose() 函数更多:

$fh = fopen($filename, 'a') or die("can't open file");
fwrite($fh, $fileNewContent);
fclose($fh);

1
这并没有涉及到OP所询问的“前置”功能。 - Erenor Paz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接