我有一个文件太大无法放入内存,需要从中剥离掉某些字符(确切来说是控制字符)。我的当前函数如下:
$old = fopen($file, 'r');
$new = fopen($tmpFile, 'w');
while (!feof($old)) {
fwrite($new, preg_replace('/[^\P{Cc}\t\r\n]/u', '', fgets($old)));
}
rename($tmpFile, $file);
这在大多数情况下都可以正常工作。但是可能会出现一个问题,即fgets
读取整行。我处理的一些文件是巨大的单行文本,这仍然会导致内存问题。
可以使用fread
来解决这个问题,块大小为8192。但是,我喂给preg_replace
的文本可能会被截断多字节字符。
我一直在思考如何在保留多字节字符的同时进行fread
,但我还没有找到一个好的解决方案。任何帮助都将是很棒的。
可能的解决方案
虽然我已经用另一种方式解决了这个问题,但我仍然对我的最初问题很感兴趣:如何做一个mb-safe的fread
?我认为这样的函数可能有效:
- 使用
fread
读取一块字节 - 检查最后一个字节,检查它是否是多字节序列的一部分。如果不是,则停在这里。
- 继续读取字节,直到最后一个字节不是多字节序列或结束当前序列。
第2步可能需要使用类似于这样的逻辑,但我对unicode并不那么熟悉。
fgetc
是二进制安全的,但不是多字节安全的。它仍然会在多字节字符上出现问题。 - Peter Kruithof