#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
andDataInputStream
?
Ответ №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 реализуют шаблон декоратора (оболочки). Каждый поток добавляет свою собственную функциональность. Попытка обернуть один и тот же «реальный» поток несколькими оболочками выглядит как попытка нарушить эту инкапсуляцию.