我有一个名为 $dir
的文件和一个名为 $line
的字符串,我知道这个字符串是该文件的一行,但我不知道它的行号,我想将其从文件中删除,该怎么办?
可以使用awk吗?
$contents = file_get_contents($dir);
$contents = str_replace($line, '', $contents);
file_put_contents($dir, $contents);
file_get_contents
获取到所有内容吗?告诉我具体哪个部分没有起作用。 - Naveed Ahmad$contents = str_replace($line."\n", '', $contents);
- Andrés Chandía$contents = str_replace($line.PHP_EOL, '', $contents);
替换。 - Andrés Chandía逐行阅读文件内容,将所有不匹配的行写入到另一个文件中。然后用新文件替换原文件。
这只是查看每一行,如果不是要删除的内容,则将其推送到一个数组中,该数组将被写回文件。参见此处。
$DELETE = "the_line_you_want_to_delete";
$data = file("./foo.txt");
$out = array();
foreach($data as $line) {
if(trim($line) != $DELETE) {
$out[] = $line;
}
}
$fp = fopen("./foo.txt", "w+");
flock($fp, LOCK_EX);
foreach($out as $line) {
fwrite($fp, $line);
}
flock($fp, LOCK_UN);
fclose($fp);
$out
构建为字符串而不是数组,然后使用file_put_contents和LOCK_EX呢?采用这种方法的原因是什么? - Cyrille不需要使用awk也可以解决:
function remove_line($file, $remove) {
$lines = file($file, FILE_IGNORE_NEW_LINES);
foreach($lines as $key => $line) {
if($line === $remove) unset($lines[$key]);
}
$data = implode(PHP_EOL, $lines);
file_put_contents($file, $data);
}
awk
。 - Nabi K.A.Z.$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);
}
$contents = file_get_contents($dir);
$new_contents = "";
if (strpos($contents, $id) !== false) { // if file contains ID
$contents_array = explode(PHP_EOL, $contents);
foreach ($contents_array as &$record) { // for each line
if (strpos($record, $id) !== false) { // if we have found the correct line
continue; // we've found the line to delete - so don't add it to the new contents.
} else {
$new_contents .= $record . "\r"; // not the correct line, so we keep it
}
}
file_put_contents($dir, $new_contents); // save the records to the file
echo json_encode("Successfully updated record!");
}
else {
echo json_encode("failed - user ID ". $id ." doesn't exist!");
}
例子:
输入:"123,学生"
旧文件:
ID,职业
123,学生
124,砖工
运行代码将更改文件为:
新文件:
ID,职业
124,砖工
$record
似乎也是不必要的。 - mickmackusa/**
* Removes the first found line inside the given file.
*
* @param string $line The line content to be searched.
* @param string $filePath Path of the file to be edited.
* @param bool $removeOnlyFirstMatch Whether to remove only the first match or
* the whole matches.
* @return bool If any matches found (and removed) or not.
*
* @throw \RuntimeException If the file is empty.
* @throw \RuntimeException When the file cannot be updated.
*/
function removeLineFromFile(
string $line,
string $filePath,
bool $removeOnlyFirstMatch = true
): bool {
// You can wrap it inside a try-catch block
$file = new \SplFileObject($filePath, "r");
// Checks whether the file size is not zero
$fileSize = $file->getSize();
if ($fileSize !== 0) {
// Read the whole file
$fileContent = $file->fread($fileSize);
} else {
// File is empty
throw new \RuntimeException("File '$filePath' is empty");
}
// Free file resources
$file = null;
// Divide file content into its lines
$fileLineByLine = explode(PHP_EOL, $fileContent);
$found = false;
foreach ($fileLineByLine as $lineNumber => $thisLine) {
if ($thisLine === $line) {
$found = true;
unset($fileLineByLine[$lineNumber]);
if ($removeOnlyFirstMatch) {
break;
}
}
}
// We don't need to update file either if the line not found
if (!$found) {
return false;
}
// Join lines together
$newFileContent = implode(PHP_EOL, $fileLineByLine);
// Finally, update the file
$file = new \SplFileObject($filePath, "w");
if ($file->fwrite($newFileContent) !== strlen($newFileContent)) {
throw new \RuntimeException("Could not update the file '$filePath'");
}
return true;
}
这里简要介绍一下正在进行的操作:获取整个文件内容,将内容分成行(即作为一个数组),查找匹配项并删除它们,将所有行连接在一起,如果有任何更改,则将结果保存回文件。
现在让我们使用它:
// $dir is your filename, as you mentioned
removeLineFromFile($line, $dir);
注意事项:
You can use fopen()
family functions instead of SplFileObject
, but I do recommend the object form, as it's exception-based, more robust and more efficient (in this case at least).
It's safe to unset()
an element of an array being iterated using foreach (There's a comment here showing it can lead unexpected results, but it's totally wrong: As you can see in the example code, $value
is copied (i.e. it's not a reference), and removing an array element does not affect it).
$line
should not have new line characters like \n
, otherwise, you may perform lots of redundant searches.
Don't use
$fileLineByLine[$lineNumber] = "";
// Or even
$fileLineByLine[$lineNumber] = null;
instead of
unset($fileLineByLine[$key]);
The reason is, the first case doesn't remove the line, it just clears the line (and an unwanted empty line will remain).
将文本转换为数组,删除第一行并重新将其转换为文本
$line=explode("\r\n",$text);
unset($line[0]);
$text=implode("\r\n",$line);
像这样:
file_put_contents($filename, str_replace($line . "\r\n", "", file_get_contents($filename)));