Используйте один входной поток в качестве источника для нескольких входных потоков более высокого уровня (например, BufferedReader, DataInputStream)

#java #tcp #stream

#java #tcp #поток

Вопрос:

я просто блуждал, была ли это хорошая или плохая идея:

 InputStreamReader in = new InputStreamReader(socket.getInputStream());
BufferedReader reader = new BufferedReader(in);
DataInputStream dis = new DataInputStream(in);
 

Теперь я хотел бы прочитать из BufferedReader. Если поступает определенная команда (просто строка), я хотел бы продолжить чтение из DataInputStream.

Работает ли это? Если да, считается ли это хорошей или плохой практикой?

Комментарии:

1. Это не будет компилироваться: вы не можете создать (Data)InputStream (на основе байтов) из InputStreamReader (на основе символов) (только наоборот: поток для чтения). Во время выполнения, скорее всего, все равно произойдет сбой из-за проблем с буферизацией — что вы хотите сделать с BufferedReader and DataInputStream ?

Ответ №1:

(Я думаю, что ваш пример нарушен с точки зрения того, что такое reader и что такое входной поток, но я все равно получаю вопрос)

Вы можете делать подобные вещи, но вам нужно точно знать, как каждый компонент ведет себя в отношении буферизации.

Входной поток сокета, с которым вы работаете, позволит вам прочитать определенный байт только один раз (проверка InputStream.markSupported() ). Вы можете обернуть этот входной поток в a BufferedInputStream , который эффективно считывает несколько байтов вперед, но также добавляет функциональность для выполнения a mark() и reset() .

Это означает, что любой поток чтения / ввода поверх BufferedInputStream может читать вперед, отмечать, пропускать назад и т.д. Но здесь вам нужно быть осторожным, чтобы не добавить еще один слой «буферов», то есть a BufferedReader > InputStreamReader > BufferedInputStream > InputStream .

Итак, ответ — да, его можно заставить работать, просто знайте точное поведение каждого компонента (я часто вижу, как люди бросают BufferedXXX его просто так).

В вашем примере я бы сделал:

 BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
InputStreamReader reader = new InputStreamReader(in, "utf-8"); // consider char encoding
DataInputStream dis = new DataInputStream(in);
 

Ответ №2:

Это не сработает.

Buffered reader считывает буферы и анализирует их как строки. Поэтому, если, например, доступно 2 с половиной строки, это, вероятно, переместит маркер потока полезной нагрузки в эту позицию. Теперь вы читаете строку, а затем решаете прочитать длинное значение, используя DataInputStream. Код попытается прочитать это значение с позиции потока полезной нагрузки (через 2,5 строки). Но вы действительно хотели прочитать число после первой строки.

Я думаю, что этот пример также объясняет, почему эта идея не является хорошей практикой. Потоки Java реализуют шаблон декоратора (оболочки). Каждый поток добавляет свою собственную функциональность. Попытка обернуть один и тот же «реальный» поток несколькими оболочками выглядит как попытка нарушить эту инкапсуляцию.