如何用php从文件中删除一行?

新手上路,请多包涵

我有一个名为 $dir 的文件和一个名为 $line --- 的字符串,我知道这个字符串是该文件的完整行,但我不知道它的行号,我想删除它来自文件,我该怎么办?

可以使用awk吗?

原文由 ibrahim 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 877
2 个回答
$contents = file_get_contents($dir);
$contents = str_replace($line, '', $contents);
file_put_contents($dir, $contents);

原文由 Naveed Ahmad 发布,翻译遵循 CC BY-SA 3.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 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题