Stream.readBytes()
readBytes() читает из потока блок байтов заданной длины и записывает их в buffer, завершаясь досрочно по таймауту, если данные не поступили.
Полная статья
Описание
readBytes() читает данные из потока и записывает их в заранее подготовленный массив. Функция завершается, когда накоплено нужное количество байтов length, или раньше — если за отведённое время данные так и не поступили. Длительность ожидания задаётся через Stream.setTimeout().
Метод определён в классе Stream и работает во всех его наследниках: Serial, Wire, сетевых клиентах и других. Подробнее об этом классе — на странице Stream.
Если read() возвращает ровно один байт за вызов, то readBytes() рассчитан на ситуации, когда нужно забрать из потока сразу целый блок: заголовок пакета, массив измерений, команду фиксированной длины или фрагмент бинарного протокола.
Синтаксис
stream.readBytes(buffer, length)
Параметры
buffer— массив, в который будут записаны прочитанные байты. Допустимые типы: массивcharилиbyte.length— количество байтов, которое нужно попытаться прочитать. Допустимый тип:size_t.
Возвращает
Число байтов, фактически записанных в буфер. Если за время ожидания не поступило ни одного байта, функция вернёт 0.
Тип возвращаемого значения: size_t.
На что обратить внимание
Возвращаемое значение может оказаться меньше запрошенного length — это штатная ситуация при таймауте. Всегда сравнивайте фактически принятое количество байтов с ожидаемым, прежде чем обрабатывать содержимое буфера: неполный пакет может привести к некорректному разбору данных.
Пример кода
В примере скетч читает до 5 символов из Serial, добавляет завершающий нулевой символ и выводит полученную строку:
char buffer[6];
void setup() {
Serial.begin(9600);
Serial.setTimeout(1000);
}
void loop() {
if (Serial.available()) {
size_t count = Serial.readBytes(buffer, 5);
buffer[count] = '\0';
Serial.print("Received: ");
Serial.println(buffer);
}
}
Где применяется
- Фиксированные пакеты — протокол заранее задаёт длину блока: 4 байта заголовка, 8 байтов полезной нагрузки и т. д.
- Бинарные протоколы — чтение массивов байтов без преобразования в текст, например показаний датчика в сыром виде.
- Команды одинаковой длины — если каждая команда всегда занимает одно и то же число байтов,
readBytes()проще и надёжнее посимвольного разбора. - Буферизация перед обработкой — сначала набрать весь блок, затем проверить контрольную сумму или разобрать поля структуры.
Практические замечания
- Функция блокирует выполнение. Пока не накоплено
lengthбайтов или не истёк таймаут, программа стоит на месте. Учитывайте это в скетчах, где важна отзывчивость. - Проверяйте возвращаемое значение. Получить меньше
lengthбайтов — нормально при таймауте. Код должен корректно обрабатывать неполный пакет, а не молча использовать «мусор» в хвосте буфера. - Следите за размером буфера. Массив должен вмещать как минимум
lengthбайтов. Если планируете работать с результатом как с C-строкой, добавьте ещё один байт под'\0'— именно так сделано в примере выше. - Нулевой символ не добавляется автоматически. Для текстовых строк завершающий
'\0'нужно поставить вручную после вызова функции. - Для данных с разделителем удобнее
readBytesUntil(). Если конец сообщения отмечен специальным символом, например'\n', лучше читать до терминатора, а не рассчитывать на фиксированную длину.
Примечания и предупреждения
readBytes() хорошо работает, когда длина ожидаемых данных известна заранее. Если размер блока непредсказуем, разумнее читать поток постепенно с помощью available() и read() или использовать чтение до символа-терминатора.