【问题标题】:PHP what is the best way to write data to middle of file without rewriting filePHP在不重写文件的情况下将数据写入文件中间的最佳方法是什么
【发布时间】:2013-05-24 16:30:39
【问题描述】:

我正在使用 php (1GB+) 中的大型文本文件,我正在使用

file_get_contents("file.txt", NULL, NULL, 100000000,100); 

要从文件中间获取数据,但如果我想将文件中的数据更改为与原始数据不同的更改,我将不得不重写整个文件。

如果数据大于原始数据,如何在不覆盖数据的情况下更改文件中的数据(可变长度)?我保留文件中不同数据块的索引及其字节位置。似乎唯一的选择是将x个字节数专用于每条数据,然后如果我想更改它则重写该块......问题在于它会占用比需要更多的空间空字节,写入需要更长的时间......这仍然无法解决如何“删除”数据,因为文件永远不会缩小大小......我真的需要一些帮助......

如果我为文件中的每条数据使用前缀块,比如 1 mb,那么我想输入的数据只有 100kb,该条目将占用 10 倍实际需要的空间,并且该条目永远无法更改到超过 1mb 的数据,因为它会覆盖超过第一个专用块......删除它是不可能的......希望这有任何意义......我不是在寻找替代品,我正在寻找修改文件中间的数据,嘿嘿……

更新:是的,我想替换旧数据,但如果新数据比旧数据扩展更多,我希望将其余数据进一步推入文件中......

考虑一下:0000000HELLODATA00000000 零代表空白空间,什么都没有......现在我想用一些东西代替你好,现在因为东西比你好,简单地写在你好的起点会延伸到你好并开始覆盖数据......所以我会像 DATA 被进一步推入文件,为某些东西腾出空间而不覆盖 DATA...呵呵

【问题讨论】:

  • fopen()、fseek() 和 fwrite() 浮现在脑海中……如果您知道文件中正在读取数据的位置,您也可以使用它而不是将完整文件加载到记忆
  • 您可以使用数据库代替文本文件。另一种方法是混合使用数据库和文本文件。将大文件分成几部分,从数据库中获取部分信息。具体实现取决于需求。
  • Ftuncate 调整文件大小然后移动数据以腾出空间stackoverflow.com/a/10467726/778719
  • 您可以将文件的内容读取到字符串中,然后使用 strlen() 来查找字符串的长度。现在您可以通过在中间添加文本来轻松找到字符串的中间形成一个新字符串。
  • 简短的回答:使用数据库。它专为基于现场的存储而设计。这正是你试图重新发明的声音。

标签: php file


【解决方案1】:

injectData() 函数的另一个变体:

function injectData($file, $data, $position) 
{
    $temp = fopen('php://temp', "rw+");
    $fd = fopen($file, 'r+b');

    fseek($fd, $position);
    stream_copy_to_stream($fd, $temp); // copy end

    fseek($fd, $position); // seek back
    fwrite($fd, $data); // write data

    rewind($temp);
    stream_copy_to_stream($temp, $fd); // stich end on again

    fclose($temp);
    fclose($fd);
}

它将文件的结尾(从$position 开始)复制到一个临时文件中,寻找回写数据并将所有内容缝合起来。

【讨论】:

  • tmpfile 实际上很慢...codepad.viper-7.com/0zaujx 将其链接到php://temp
  • rename 也会使第二个示例变慢
  • @Baba 我根本不需要ftruncate() :)
  • 为什么我们在这里使用两个文本文件?
【解决方案2】:

Baba 答案的一个变体,不确定在处理较大的文件时是否会更有效:

function injectData($file, $data, $position) {
    $fpFile = fopen($file, "rw+");
    $fpTemp = fopen('php://temp', "rw+");
    stream_copy_to_stream($fpFile, $fpTemp, $position);
    fwrite($fpTemp, $data);
    stream_copy_to_stream($fpFile, $fpTemp, -1, $position);

    rewind($fpFile);
    rewind($fpTemp);
    stream_copy_to_stream($fpTemp, $fpFile);

    fclose($fpFile);
    fclose($fpTemp);
}

injectData('testFile.txt', 'JKL', 3);

我早期方法的变体,它消除了一个 stream_copy_to_stream() 调用,因此应该更快:

function injectData3($file, $data, $position) {
    $fpFile = fopen($file, "rw+");
    $fpTemp = fopen('php://temp', "rw+");
    stream_copy_to_stream($fpFile, $fpTemp, -1, $position);
    fseek($fpFile, $position);
    fwrite($fpFile, $data);
    rewind($fpTemp);
    stream_copy_to_stream($fpTemp, $fpFile);

    fclose($fpFile);
    fclose($fpTemp);
}

【讨论】:

  • streamcopy #1 复制源文件到位置; streamcopy #2 从位置复制源文件; streamcopy #3 将 temp 复制回源...避免将文件系统用于较小的文件
  • 仍然不知道它对大文件的处理能力如何......今晚可能会实际运行一些测试,看看它是否适用于“实时”工作构建 ISAM 文件
  • 目前正在运行测试 .. 也会向您更新我的调查结果...但这是迄今为止我对小文件的了解codepad.viper-7.com/0zaujx
  • 很好的更新.. 1,000,000 迭代 codepad.viper-7.com/Yl1q9y
  • 我希望我能给你更多的支持......这可能是最高效的解决方案:)
【解决方案3】:

覆盖数据:

$fp = fopen("file.txt", "rw+");
fseek($fp, 100000000); // move to the position
fwrite($fp, $string, 100); // Overwrite the data in this position 
fclose($fp);

注入数据

这很棘手,因为您必须rewrite 文件。可以用partial modificationfrom point of injection而不是整个文件进行优化

$string = "###INJECT THIS DATA ##### \n";
injectData("file.txt", $string, 100000000);

使用的功能

function injectData($file, $data, $position) {
    $fpFile = fopen($file, "rw+");
    $fpTemp = fopen('php://temp', "rw+");

    $len = stream_copy_to_stream($fpFile, $fpTemp); // make a copy

    fseek($fpFile, $position); // move to the position
    fseek($fpTemp, $position); // move to the position

    fwrite($fpFile, $data); // Add the data

    stream_copy_to_stream($fpTemp, $fpFile); // @Jack

    fclose($fpFile); // close file
    fclose($fpTemp); // close tmp
}

【讨论】:

  • 这是可行的,但它不会从指定的点覆盖字符而不是插入吗?我认为问题的第二段是指在不丢失旧值的情况下写入新数据。不过不确定...
  • 更新答案以反映数据注入
  • 为什么我们在这里使用两个文本文件?
  • @shashiverma 你在哪里看到的文本文件?
  • 对不起,我说的是“php://temp”。在“php://temp”的地方,我链接了一个文本文件(abc.txt),每当我调用函数时它将所有数据从 $file 复制到 abc.txt 文件并更新 $file。如果我删除第二个文件(“php://temp”或“abc.txt”)的操作,则 $string 不会被附加它覆盖内容的文件。
猜你喜欢
  • 1970-01-01
  • 2011-06-15
  • 2020-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
  • 2011-03-16
  • 2020-09-26
相关资源
最近更新 更多