>问题
如果我没有足够的空间在RAM 中分配数据,并且没有足够的空间在当前 FS 分区上复制它,如何将数据写入文件开头? 即我有一个大小100Mb
的文件,我的 PHP 脚本中有30Mb
内存限制(并且无法以任何方式调整(,并且我当前的 FS 分区上只有50Mb
可用空间。我想在文件中添加 2-10 行(绝对小于剩余的 50Mb FS 空间(
一些背景
我知道XY问题,并同意这种情况是正确的。但是要重新考虑这种情况,我需要更改当前应用程序的重要部分(实际上,它来自以前的团队(,并且可能是使用此文件的其他应用程序的 API。
我的尝试
我还没有找到解决方案。我以前的方法是 - 使用一些网络缓冲区(即连接到一些外部存储,例如 MySQL - 它位于另一台有足够的空间写入文件副本的机器上(
问题
那么,当我没有足够的空间在 RAM 中分配数据并且没有足够的空间在 FS 上创建文件的副本时,是否可以将数据写入文件的启动?使用网络(外部(存储是唯一的解决方案吗?
假设您想将 2K 写入文件的开头,您唯一真正的选择是:
- 打开文件
- 从文件末尾读取尽可能多的内存
- 在开始读取后 2K 将其写回文件
- 继续上一个数据块,直到将文件的全部内容向末尾移动 2K
- 把你的 2K 写到开头
要可视化:
|------------------------|
|-----------------XXXXXXX|
------>
|-------------------XXXXXXX|
|----------XXXXXXX---------|
------>
|------------XXXXXXX-------|
...repeat...
请注意,这是一个非常不安全的操作,它会就地编辑文件。如果进程崩溃,您将留下一个处于不一致状态的文件。如果磁盘上没有足够的空间来复制文件,则可能不应该使用该文件并首先扩展存储容量。
@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
文件(
感谢所有参与此活动的人。
我已经尝试了@AlmaDo建议的代码,不要在实际项目中尝试,否则你会在地狱中被烧毁,它非常慢。(60MB 文件 - 处理 19 分钟(
你可以运行shell脚本-https://stackoverflow.com/a/9533736/2064576(处理420ms,无法理解它使用了多少内存(或者试试这个php脚本 - https://stackoverflow.com/a/16813550/2064576(160ms,使用memory_limit = 3M,不适用于2M(