直接读取+重排+写入最稳妥:php无原生就地排序函数,file()+usort()适合中小文件,需用FILE_IGNORE_NEW_LINES等标志;大文件应流式处理或调用系统sort命令。

直接读取+重排+写入是最稳妥的做法
PHP 没有原生“就地修改文件行顺序”的函数,fgets() 或 file() 读出来的是数组,排序必须在内存中完成,再用 file_put_contents() 覆盖写回。试图用 fseek() + fwrite() 手动挪动行位置极易出错——换行符长度不一致(n vs rn)、编码空格、bom 头都会导致偏移错乱。
file() + usort() 是最常用组合
适用于中小文件(几百 MB 以内),代码简洁且可控。注意默认 file() 会保留换行符,排序后若需保持格式统一,建议先 rtrim() 再排序,最后手动补 n:
$lines = file('data.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); usort($lines, function($a, $b) { return strcmp($a, $b); // 字典序 // 或 intval($a) <=> intval($b); // 数值序(PHP 7+) }); file_put_contents('data.txt', implode("n", $lines) . "n");
-
FILE_IGNORE_NEW_LINES避免每行末尾带n干扰比较 -
FILE_SKIP_EMPTY_LINES过滤空行,防止strcmp('', 'xxx')返回意外结果 - 数值排序别直接用
sort($lines, SORT_NUMERIC)—— 它对字符串数字(如"10")排序不稳定,usort+ 强制转换更可靠
大文件慎用 file(),改用流式逐行读取+临时文件
超过 500MB 的文件,file() 可能触发内存耗尽(Allowed memory size exhausted)。此时应放弃一次性加载,改用 fopen() + fgets() 流式读取,把行内容和原始位置(或哈希)存到外部索引(如 sqlite 或临时 CSV),排序后再按序读取源文件写入新文件:
$fp = fopen('big.txt', 'r'); $tempLines = []; while (($line = fgets($fp)) !== false) { $tempLines[] = rtrim($line, "rn"); } fclose($fp); // 排序... file_put_contents('big_sorted.txt', implode("n", $tempLines) . "n");
- 虽然仍全量载入内存,但至少避免了
file()自动加n的副作用 - 真超大文件(GB 级)需配合外部排序工具(如系统
sort命令),PHP 只做调度:exec('sort -o sorted.txt big.txt'); - 注意
fgets()在 windows 下对rn的处理比file()更干净,不易多出空行
按某列排序(如 CSV 第三列)要先解析再比
直接对 CSV 行字符串排序会出错(比如按字典序排数字列,“100” 会排在 “2” 前面)。必须用 str_getcsv() 拆解,提取目标字段再比较:
立即学习“PHP免费学习笔记(深入)”;
$lines = file('data.csv', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); usort($lines, function($a, $b) { $aCols = str_getcsv($a); $bCols = str_getcsv($b); return $aCols[2] <=> $bCols[2]; // 按第3列(索引2)数值排序 }); file_put_contents('data.csv', implode("n", $lines) . "n");
-
str_getcsv()自动处理带引号、逗号转义的 CSV,比explode(',', $line)安全得多 - 若列含空值,
$aCols[2]可能未定义,建议加?? ''或array_key_exists(2, $aCols)判断 - UTF-8 编码下,
str_getcsv()默认按字节解析,遇到多字节字符(如中文)一般没问题;但若 CSV 用 BOM 开头,file()读出的首行可能含xEFxBBxBF,需提前ltrim($line, "xEFxBBxBF")
实际改行序最常卡在换行符不一致和 CSV 字段嵌套上,这两处不处理,排序结果看着正常,一导入 excel 就错位。