Вы можете написать посимвольный цикл накопления, который (а) помещает строки поля в массив, когда он встречает запятые, и (b) вызывает функцию для сохранения накопленных строк поля в базу данных mysql, когда он находит указатель записи. :
while($c = fgetc($fp)) {
if($c == ',') {
$fields[] = implode(null,$accumulator);
$accumulator = array();
} else if($c == '\\') {
save_fields_to_mysql($fields);
$fields = array();
$accumulator = array();
} else
$accumulator[] = $c;
}
Это, вероятно, сработает для вас, если вы уверены, что ваши поля никогда не содержат вашего поля или разделителей записей в качестве данных.
Если это возможно, вам нужно придумать escape-последовательность для представления литеральных значений вашего поля и разделителя записей (и, возможно, также вашей escape-последовательности). Давайте предположим, что это так, и примем знак% в качестве escape-символа:
define('ESCAPED',1);
define('NORMAL',0);
$readState = NORMAL;
while($c = fgetc($fp)) {
if($readState == ESCAPED) {
$accumulator[] = $c;
$readState = NORMAL;
} else if($c == '%') {
$readState = ESCAPED;
} else if($c == ',') {
$fields[] = implode(null,$accumulator);
$accumulator = array();
} else if($c == '\\') {
save_fields_to_mysql($fields);
$fields = array();
$accumulator = array();
} else
$accumulator[] = $c;
}
т. Е. Любое вхождение% устанавливает переменную состояния, которая указывает на следующем проходе цикла, какой бы символ мы ни читали, он будет восприниматься как литеральные данные, которые являются частью поля, а не символом.
Это должно поддерживать минимальное использование памяти.
[Обновить] Как насчет эффективности ввода / вывода?
Один комментатор правильно указал, что эта иллюстрация довольно интенсивно использует ввод-вывод, и, поскольку ввод-вывод, как правило, является наиболее дорогостоящей операцией с точки зрения времени, вполне возможно, что это не будет приемлемым решением.
На другом конце спектра у нас есть опция буферизации всего файла в памяти, которая включает в себя оригинальные решения с интенсивным использованием памяти, о которых Аскер упоминал, но хотел избежать. Счастливый носитель, вероятно, находится где-то посередине: мы можем использовать предел чтения, который вы можете передать в качестве второго аргумента fgets()
, чтобы набрать несколько большое (но не до смешного большого) количество символов в одном вводе-выводе и затем обрабатывать этот буфер посимвольно вместо потока ввода-вывода, заполняя его, когда мы прожигаем буфер.
Это действительно делает процесс чтения немного более интенсивным, чем $c = fgetc($fp)
, потому что вы должны следить за тем, где вы находитесь в буфере и насколько заполнен буфер, а также где вы в файле. Вы можете сделать это с помощью ряда флагов и индексных переменных внутри цикла чтения, если хотите, но может быть удобнее иметь абстракцию примерно так:
class StrBufferedChrReader {
private $_filename;
private $_fp;
private $_bufferIdx;
private $_bufferMax = 2048;
private $_buffer;
function __construct($filename=null,$bufferMax=null) {
if($bufferMax) $this->_bufferMax = $bufferMax;
if($filename) $this->open($filename);
}
function _refillBuffer() {
if($this->_fp) {
$this->_buffer = fgets($this->_fp,$this->_bufferMax + 1);
$this->_bufferIdx = 0;
return $this->_buffer;
}
return false;
}
function open($filename=null) {
if($filename) $this->_filename = $filename;
if($this->_fp = fopen($this->_filename))
$this->_refillBuffer();
return $this->_fp;
}
function getc() {
if($this->_bufferIdx == $this->_bufferMax)
if(!$this->_refillBuffer())
return false;
return $this->_buffer[$this->_bufferIdx++];
}
function close() {
$this->_buffer = null;
$this->_bufferIdx = null;
return fclose($this->_fp);
}
}
Что вы можете использовать в любом из вышеприведенных циклов, например:
$r = new StrBufferedChrReader($filename,$bufferSize);
while($c = $r->getc()) {
...
Примерно так можно выделить много разных точек вдоль континуума между решением с интенсивным использованием памяти и решением с интенсивным вводом / выводом, изменив значение $ bufferSize. Больше $ bufferSize, больше использования памяти, меньше операций ввода-вывода. Меньший $ bufferSize, меньшее использование памяти, больше операций ввода-вывода.
(Примечание: не думайте, что урок готов к работе. Он предназначен для иллюстрации возможной абстракции, может содержать отдельные или другие ошибки. Может вызвать помутнение зрения, недостаток сна, учащенное сердцебиение, или другие побочные эффекты. Проконсультируйтесь с врачом и проведите тестирование перед использованием.)