Я пытаюсь использовать только fopen()
а также fseek()
чтобы получить конкретные строки кода (не только одну строку, мне нужно получить строку выше и ниже текущей строки поиска).
Чтобы улучшить производительность, я знаю, как получить конкретную строку для поиска и затем выйти. Если мне нужна строка 5, то следует искать 4 и 6.
Вот код для получения байтов каждой строки, которые затем помещаются в массив в виде строк в качестве ключа и значения в виде байтов для EOF
,
$fh = fopen($source, 'r');
$meta = stream_get_meta_data($fh);
if (!$meta['seekable']) {
throw new Exception(sprintf("A source is not seekable: %s", print_r($source, true)));
}
$line = fgets($fh, 4096);
$pos = -1;
$i = 0;
$result = null;
$linenum = 10;
var_dump('Line num:'.$linenum);
$total_lines = null;
// Get seek byte end of each line
while (!feof($fh)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
$total_lines[$i] = $pos;
$pos++;
} else {
$i++;
}
//var_dump(fgets($fh).' _ '.$pos);
}
// Now get specific lines (line 5, line 6 and line 7)
$seekssearch = array($total_lines[5], $total_lines[6], $total_lines[7]);
$result = null;
$posr = 0;
foreach ($seekssearch as $sk) {
while (!feof($fh)) {
if ($char != "\n" && $char != "\r") {
fseek($fh, $sk, SEEK_SET);
$posr++;
} else {
$ir++;}
}
// Merge result of line 5,6 and 7
$result .= fgets($fh);
}
echo $result;
exit;while (!feof($fh) && $i<($linenum)) {
$char = fgetc($fh);
if ($char != "\n" && $char != "\r") {
fseek($fh, $pos, SEEK_SET);
$pos++;
}
else {
$i++;
}
}
$line = trim(fgets($fh));
var_dump($line);
exit;exit;
while (!feof($fh) && $i<($linenum-1)) {
$char = fgetc($fh);if ($char != "\n" && $char != "\r") {
//fseek($fh, $pos);
fseek($fh, $pos);
$pos++;
}
else {
if ($pos == 3) {
$line = fgets($fh);
}
$i++;}
}
//$line = fgets($fh);
var_dump($line); exit;
Как объединить эти строки?
Примечание: я не хочу использовать
splFileInfo
или любые трюки, такие как массивы. Просто хочу потом выйти.
Я создал функцию, которая читает файл, подсчитывает строки и сохраняет в массивах каждую строку байтов для поиска. Если максимум указан linenum
установлен, он будет прерываться, чтобы сохранить производительность, чем в новой функции цикла для поиска позиции в байтах для получения содержимого файла.
Я считаю, что эта функция может улучшиться.
function readFileSeek($source, $linenum = 0, $range = 0)
{
$fh = fopen($source, 'r');
$meta = stream_get_meta_data($fh);
if (!$meta['seekable']) {
throw new Exception(sprintf("A source is not seekable: %s", print_r($source, true)));
}
$pos = 2;
$result = null;
if ($linenum) {
$minline = $linenum - $range - 1;
$maxline = $minline+$range+$range;
}
$totalLines = 0;
while (!feof($fh)) {
$char = fgetc($fh);
if ($char == "\n" || $char == "\r") {
++$totalLines;
} else {
$result[$totalLines] = $pos;
}
$pos++;
if ($maxline+1 == $totalLines) {
// break from while to not read entire file
break;
}
}
$buffer = '';
for ($nr=$minline; $nr<=$maxline; $nr++) {
if (isset($result[$nr])) {
fseek($fh, $result[$nr], SEEK_SET);
while (!feof($fh)) {
$char = fgetc($fh);
if ($char == "\n" || $char == "\r") {
$buffer .= $char;
break;
} else {
$buffer .= $char;
}
}
}
}
return $buffer;
}
Результаты теста (файл 1,3 ГБ, 100000000 строк кода, поиск до 300000 строк кода):
string(55) "299998_abc
299999_abc
300000_abc
300001_abc
300002_abc
"
Time: 612 ms, Memory: 20.00Mb
$ ll -h /tmp/testReadSourceLines_27151460344/41340913936
-rw-rw-r-- 1 1,3G /tmp/testReadSourceLines_27151460344/41340913936
Других решений пока нет …