Главная chevron_right Функции chevron_right Связь chevron_right Stream.readBytesUntil()

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' и не выйти за границы буфера.