Stream.readBytesUntil()
readBytesUntil() читает байты из потока в buffer, останавливаясь при встрече символа-терминатора character, заполнении length байтов или истечении таймаута — и возвращает фактическое число прочитанных байтов.
Полная статья
Описание
readBytesUntil() — удобный способ читать данные из потока порциями, ориентируясь на разделитель. Функция записывает байты в buffer до тех пор, пока не произойдёт одно из трёх: встретится символ-терминатор character, будет прочитано length байтов, или истечёт таймаут (настраивается через Stream.setTimeout()).
Когда терминатор найден, он извлекается из потока, но в буфер не попадает и в возвращаемое значение не входит. Если же чтение остановилось из-за достижения length, следующий байт в потоке остаётся нетронутым — его можно будет прочитать следующим вызовом.
Метод определён в классе Stream и доступен во всех его наследниках: Serial, Wire, сетевых клиентах и других. Подробнее об иерархии классов — на странице Stream.
Синтаксис
stream.readBytesUntil(character, buffer, length)
Параметры
character— символ, при встрече которого чтение прекращается. Тип данных:char.buffer— массив, куда записываются прочитанные байты. Допустимые типы: массивcharилиbyte.length— максимальное число байтов, которое можно поместить в буфер. Тип данных:size_t.
Возвращает
Фактическое количество байтов, записанных в буфер. Символ-терминатор в это число не включается. Если поток был пуст или терминатор встретился самым первым байтом, функция вернёт 0.
Тип данных: size_t.
Пример кода
В примере ниже скетч читает строку из Serial до символа новой строки:
char line[32];
void setup() {
Serial.begin(9600);
Serial.setTimeout(1000);
}
void loop() {
if (Serial.available()) {
size_t count = Serial.readBytesUntil('\n', line, sizeof(line) - 1);
line[count] = '\0';
Serial.print("Line: ");
Serial.println(line);
}
}
Где применяется
- Построчное чтение из Serial Monitor — получать ввод пользователя до символа
'\n', который терминал добавляет при нажатии Enter. - Текстовые протоколы с разделителем — разбирать поля, разделённые
',',';','#'или любым другим символом. - Ответы внешних модулей — считывать одну строку ответа от GPS-модуля, GSM-модема или другого устройства, общающегося по UART.
- Защита от переполнения буфера — ограничивать чтение параметром
length, чтобы данные гарантированно уместились в массив.
Практические замечания
- Буфер не завершается нулём автоматически. Если вы хотите работать с результатом как с C-строкой, добавьте
'\0'вручную после вызова — и заранее выделите в массиве на один байт больше. - Возвращаемое значение может быть меньше
length. Это штатная ситуация: чтение завершилось по терминатору или таймауту, а не обязательно по заполнению буфера. - Терминатор потребляется только при обнаружении. Если буфер заполнился раньше, чем встретился терминатор, он останется в потоке и будет доступен при следующем чтении.
- Функция блокирует выполнение. Пока данных недостаточно, скетч стоит на месте до истечения таймаута. Чтобы избежать лишних задержек, перед вызовом можно проверить
available(). - Если терминатора нет — используйте
readBytes(). Когда протокол передаёт данные фиксированной длины без разделителя, проще читать ровно нужное количество байтов.
Примечания и предупреждения
Передавайте в параметр length значение, которое не превышает реальный размер массива. Для строк принято использовать sizeof(buffer) - 1, чтобы зарезервировать место под завершающий '\0' и не выйти за границы буфера.