PHP多行文件处理需统一换行符、正确编码转换、流式处理大文件、保留权限与BOM:先用str_replace归一为\n,正则跨行匹配加s修饰符,大文件用分块读取,编码用mb_detect_encoding识别并转换,写回时chmod保持权限,读前3字节检测BOM。

PHP读取文件时遇到换行符不一致怎么办
Windows用\r\n,Linux/macOS用\n,直接用str_replace替换多行字符串大概率失败——因为目标文本里可能是"abc\r\n123",而你写的替换模板却是"abc\n123"。
正确做法是统一规范化换行符再操作:
- 用
file_get_contents读取后,先用str_replace(["\r\n", "\r"], "\n", $content)归一化 - 替换目标也按
\n写,比如"header\nversion: 1.0\nfooter" - 写回文件前,按目标系统选换行符:
PHP_OS_FAMILY === 'Windows' ? str_replace("\n", "\r\n", $new) : $new
用preg_replace安全匹配跨行内容
str_replace无法处理“开头固定、中间任意、结尾固定”的多行块(比如注释块、配置段),必须用正则,但默认.不匹配换行符。
关键参数是s修饰符(PCRE_DOTALL):
立即学习“PHP免费学习笔记(深入)”;
$pattern = '/<!-- START BLOCK -->(.*?)<!-- END BLOCK -->/s'; $content = preg_replace($pattern, $replacement, $content);
注意点:
- 务必加
s,否则.*?跨不过\n - 用
.*?而非.*,避免贪婪匹配到最远的结束标记 - 如果内容含
/,改用其他分隔符,比如#<!-- START #s
大文件不能全载入内存:用stream_filter_append边读边替
几百MB的日志或SQL文件,file_get_contents直接OOM。得流式处理。
核心是注册自定义过滤器:
$fp = fopen('big.log', 'r+');
stream_filter_append($fp, 'string.rot13'); // 示例,实际要自己写filter
更实用的做法是分块读取+缓冲区拼接:
- 用
fopen打开,fgets逐行读,但需维护一个$buffer暂存可能跨行的待匹配片段 - 比如匹配
"BEGIN\n.*?\nEND",读到BEGIN就开启缓冲,直到遇到END才整体替换 - 用
fseek和fwrite原地修改风险高,建议输出到新文件,再rename
替换后文件权限/编码丢失怎么恢复
file_put_contents默认用UTF-8写,若原文件是GBK或ISO-8859-1,中文直接变乱码;chmod也不继承原文件权限。
必须显式处理:
- 读取前用
mb_detect_encoding($content, ['UTF-8', 'GBK', 'BIG5'], true)猜编码,再mb_convert_encoding转UTF-8处理,写回前转回去 - 用
fileperms($file)读权限,file_put_contents后立刻chmod($new_file, fileperms($file)) - 保留所有元信息(如BOM头):读取时用
file_get_contents($file, false, null, 0, 3)判断前3字节是否\xEF\xBB\xBF
多行替换看着简单,真正落地时换行符、编码、大文件、权限这四点漏一个,生产环境就出问题。



















