我有一个名为 $dir
的文件和一个名为 $line
--- 的字符串,我知道这个字符串是该文件的完整行,但我不知道它的行号,我想删除它来自文件,我该怎么办?
可以使用awk吗?
原文由 ibrahim 发布,翻译遵循 CC BY-SA 4.0 许可协议
这里的所有答案都有一个共同点,就是将完整的文件加载到内存中。这是在 不将文件内容复制到变量 的情况下删除一个(或多个)行的实现。
这个想法是遍历文件行。如果应该删除一行,则将行长度添加到 $byte_offset
。然后将下一行 $byte_offset
字节“向上”移动。这是通过以下所有行完成的。如果所有行都已处理,则文件最后 $byte_offset
字节将被删除。
我想这对于更大的文件来说更快,因为没有任何内容被复制。而且我猜想在某些文件大小下,其他答案根本不起作用,而这个答案应该起作用。但我没有测试它。
用法:
$file = fopen("path/to/file", "a+");
// remove lines 1 and 2 and the line containing only "line"
fremove_line($file, 1, 2, "line");
fclose($file);
fremove_line()
函数的代码:
/**
* Remove the `$lines` by either their line number (as an int) or their content
* (without trailing new-lines).
*
* Example:
* ```php
* $file = fopen("path/to/file", "a+"); // must be opened writable
* // remove lines 1 and 2 and the line containing only "line"
* fremove_line($file, 1, 2, "line");
* fclose($file);
* ```
*
* @param resource $file The file resource opened by `fopen()`
* @param int|string ...$lines The one-based line number(s) or the full line
* string(s) to remove, if the line does not exist, it is ignored
*
* @return boolean True on success, false on failure
*/
function fremove_line($file, ..$lines): bool{
// set the pointer to the start of the file
if(!rewind($file)){
return false;
}
// get the stat for the full size to truncate the file later on
$stat = fstat($file);
if(!$stat){
return false;
}
$current_line = 1; // change to 0 for zero-based $lines
$byte_offset = 0;
while(($line = fgets($file)) !== false){
// the bytes of the lines ("number of ASCII chars")
$line_bytes = strlen($line);
if($byte_offset > 0){
// move lines upwards
// go back the `$byte_offset`
fseek($file, -1 * ($byte_offset + $line_bytes), SEEK_CUR);
// move the line upwards, until the `$byte_offset` is reached
if(!fwrite($file, $line)){
return false;
}
// set the file pointer to the current line again, `fwrite()` added `$line_bytes`
// already
fseek($file, $byte_offset, SEEK_CUR);
}
// remove trailing line endings for comparing
$line_content = preg_replace("~[\n\r]+$~", "", $line);
if(in_array($current_line, $lines, true) || in_array($line_content, $lines, true)){
// the `$current_line` should be removed so save to skip the number of bytes
$byte_offset += $line_bytes;
}
// keep track of the current line
$current_line++;
}
// remove the end of the file
return ftruncate($file, $stat["size"] - $byte_offset);
}
原文由 miile7 发布,翻译遵循 CC BY-SA 4.0 许可协议
1 回答4.1k 阅读✓ 已解决
3 回答1.9k 阅读✓ 已解决
2 回答2.3k 阅读✓ 已解决
2 回答776 阅读✓ 已解决
1 回答1.4k 阅读✓ 已解决
2 回答2.3k 阅读
1 回答695 阅读✓ 已解决