2

问题

如果我没有足够的空间在 RAM 中分配数据并且我没有足够的空间将其复制到当前 FS 分区上,如何将数据写入文件的开头?即我有一个有100Mb大小的文件,30Mb我的 PHP 脚本中有内存限制(不能以任何方式调整),50Mb我当前的 FS 分区只有空闲。我想在文件中添加 2-10 行(绝对小于剩余的 50Mb FS 空间)

一些背景

我知道XY 问题,并同意这种情况是正确的。但是要重新考虑这种情况,我需要更改当前应用程序的重要部分(实际上,它来自以前的团队),并且可能是使用此文件的其他应用程序的 API。

我的尝试

我还没有找到解决方案。我以前的方法是 - 使用一些网络缓冲区(例如,连接到一些外部存储,例如 MySQL - 它位于另一台有足够空间写入文件副本的机器上)

问题

那么,当我没有足够的空间在 RAM 中分配数据并且没有足够的空间在 FS 上创建文件的副本时,是否可以将数据写入文件的开头?使用网络(外部)存储是唯一的解决方案吗?

4

3 回答 3

2

假设您想将 2K 写入文件的开头,您唯一真正的选择是:

  • 打开文件
  • 从文件末尾读取尽可能多的内容
  • 将其写回文件比您开始阅读的时间晚 2K
  • 继续前一个数据块,直到您将文件 2K 的全部内容移向末尾
  • 把你的 2K 写到开头

可视化:

|------------------------|

|-----------------XXXXXXX|
                  ------>

|-------------------XXXXXXX|

|----------XXXXXXX---------|
           ------>

|------------XXXXXXX-------|

...repeat...

请注意,这是一个非常不安全的操作,它会就地编辑文件。如果进程崩溃,您会留下一个处于不一致状态的文件。如果磁盘上没有足够的空间来复制文件,则可以说不应该使用该文件并首先扩展存储容量。

于 2013-09-29T12:02:19.057 回答
1

@deceze 提示我好主意。所以我完成了:

function reverseFile($sIn, $sOut, $bRemoveSource=false)
{
        $rFile = @fopen($sIn, 'a+');
        $rTemp = @fopen($sOut,'a+');
        if(!$rFile || !$rTemp)
        {
                return false;
        }
        $iPos = filesize($sIn)-1;
        while($iPos>=0)
        {
                fseek($rFile, $iPos, SEEK_SET);
                fwrite($rTemp, $tmp=fread($rFile, 1));
                ftruncate($rFile, $iPos>0?$iPos:0);
                clearstatcache();
                $iPos--;
        }
        fclose($rFile);
        fclose($rTemp);
        if($bRemoveSource)
        {
                unlink($sIn);
        }
        return true;
}

function writeReverse($sFile, $sData, $sTemp=null)
{
        if(!isset($sTemp))
        {
                $sTemp=$sFile.'.rev';
        }
        if(reverseFile($sFile, $sTemp, 1))
        {
                file_put_contents($sTemp, strrev($sData), FILE_APPEND);
                return reverseFile($sTemp, $sFile, 1);
        }
        return false;
}

- 它会很慢,但如果进程被中断可以恢复(只需查看.rev文件)

感谢所有参与此活动的人。

于 2013-09-29T13:07:26.427 回答
0

我已经尝试过@AlmaDo 建议的代码,不要在实际项目中尝试,否则你会被烧死,它非常慢。(60MB 文件 - 处理 19 分钟)

您可以运行 shell 脚本 - https://stackoverflow.com/a/9533736/2064576(处理 420 毫秒,无法理解它使用了多少内存)或尝试这个 php 脚本 - https://stackoverflow.com/a/16813550 /2064576(160ms,使用 memory_limit=3M,不使用 2M)

于 2015-01-25T15:37:06.543 回答