【问题标题】:Write data to start of file when not enough space空间不足时将数据写入文件开头
【发布时间】:2013-10-05 07:56:10
【问题描述】:

问题

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

一些背景

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

我的尝试

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

问题

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

【问题讨论】:

标签: php file


【解决方案1】:

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

可以运行shell脚本-https://stackoverflow.com/a/9533736/2064576(处理了420ms,看不懂占用了多少内存) 或者试试这个 php 脚本 - https://stackoverflow.com/a/16813550/2064576(160ms,使用 memory_limit=3M,不使用 2M)

【讨论】:

    【解决方案2】:

    @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 文件)

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

    【讨论】:

      【解决方案3】:

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

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

      形象化:

      |------------------------|
      
      |-----------------XXXXXXX|
                        ------>
      
      |-------------------XXXXXXX|
      
      |----------XXXXXXX---------|
                 ------>
      
      |------------XXXXXXX-------|
      
      ...repeat...
      

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

      【讨论】:

      • 是的,我喜欢这个,因为它至少会工作。而且我正在考虑您提到的案例-如果写作过程会被中断怎么办
      • 再次感谢您 - 我受到您的想法的启发,并创建了安全的方法来做到这一点。
      猜你喜欢
      • 2018-04-23
      • 2010-11-15
      • 2016-04-04
      • 2013-02-03
      • 1970-01-01
      • 2016-12-19
      • 2019-10-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多