System.out закрыт? Могу ли я снова открыть его?
Я помогал другу написать код Java, который мало знает о Java. Поэтому я написал ему некоторые вспомогательные функции, чтобы легко сделать все, что было немного необычно в его глазах. Одна из них - это функция, которая записывает строку в OutputStream
. Посмотрите:
public void write(String txt, OutputStream out) {
PrintWriter printer = new PrintWriter(out);
printer.print(txt);
printer.close();
}
Теперь вы можете использовать это легко по-разному, чтобы писать везде, где хотите. Например, вы можете сделать это:
(new StreamHelper()).write("Hello Test", System.out);
Сделав это, я узнал, что впоследствии System.out.println()
больше ничего не пишет в оболочку. Поэтому я думаю, что, возможно, printer.close()
автоматически также закрывается System.out
, и мне интересно, как его активировать, чтобы я мог использовать его после завершения этой функции.
Является ли мое предположение правильным? (Как я мог узнать, не спрашивая здесь?)
Как я могу продолжать использовать System.out
после вызова функции write()
?
Есть ли лучшие способы написать такую вспомогательную функцию?
Ответы
Ответ 1
Общий контракт для OutputStream
close:
public void close() throws IOException Закрывает этот выходной поток и освобождает любые системные ресурсы, связанные с этим потоком. Общий контракт close заключается в том, что он закрывает выходной поток. Закрытый поток не может выполнять выходные операции и не может быть повторно открыт.
PrintStream
's
public void close() Закрыть поток. Это делается путем промывки поток, а затем закрытие основного потока вывода.
Единственный совет, который я могу вам дать, заключается в том, что вам не следует писать асимметричный код, то есть не делегировать закрытие ресурсов вашим код создан в другом месте.
Даже если в вашем случае может показаться разумным закрыть поток обертки, факт в том, что вы не должны, потому что вы закрываете поток, открытый где-то еще.
Короче:
public void write(String txt, OutputStream out) {
PrintWriter printer = new PrintWriter(out);
printer.print(txt);
printer.flush();
//it is very unpolite to close someone else streams!
//printer.close();
}
О, и, кстати, вы можете изменить имя функции на print
, а не на write
.
Ответ 2
Как и другие, поток должен быть закрыт там, где он был открыт. Однако вы можете написать фасад, чтобы защитить поток от закрывания:
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class UnclosableOutputStream extends FilterOutputStream {
public UnclosableOutputStream(OutputStream out) {
super(out);
}
@Override
public void close() throws IOException {
out.flush();
}
}
и используйте его следующим образом:
new StreamHelper().write("Hello Test", new UnclosableOutputStream(System.out));
Может оказаться полезным для тестовых сценариев и т.д.
Ответ 3
System.out
- это PrintStream, поэтому код, который вы предоставили выше, не имеет никакого преимущества перед тем, как просто позвонить System.out.print
напрямую. Причина, по которой он больше не пишет, заключается в том, что close
действительно закрыл System.out
.
Если это для ведения журнала, узнайте log4j для своего друга или помогите ему узнать его. Log4j обрабатывает ситуации, когда вам достаточно хорошо писать в поток файлов, стандартную и т.д. Одновременно.
Ответ 4
Вы можете проверить, прошел ли вход out
System.out
и выборочно решить не закрывать.
Требуется вызов flush()
. Обратите внимание, что я выполняю проверку ==
, так как ссылки будут идентичными, если вы должны были вызвать этот метод write
с аргументом System.out
.
public void write(String txt, OutputStream out) {
PrintWriter printer = new PrintWriter(out);
printer.print(txt);
printer.flush();
if(out != System.out) {
printer.close();
}
}
Но, честно говоря, я бы придерживался другого метода закрытия или вызова этого метода writeAndClose
, чтобы избежать путаницы.
Если вы хотите сохранить абстракцию (как намечено @Urs), сделайте следующее. Но я не вижу смысла в этом довольно сложном
public void write(String txt, OutputStream out) {
PrintWriter printer = new PrintWriter(out);
printer.print(txt);
printer.flush();
}
public void close(OutputStream out) {
out.close();
}
Ответ 5
Посмотрите на это с точки зрения вызывающего абонента.
Вызывающий имеет OutputStream
своего рода, и вызывает метод с именем write()
. После завершения вызова вызывающий абонент обнаруживает, что поток был закрыт.
На мой взгляд, ваш метод write()
просто не должен вызывать printer.close()
. Последний закрывает поток, предоставляемый вызывающим абонентом, и, вероятно, не тот, который ожидает абонент.
Если вам нужно очистить поток, вы можете использовать flush()
.
Ответ 6
Сделайте то, что предлагает Стас Курилин.
В общем, потоки должны быть закрыты стороной, открывшей/создавшей их.
В вашем методе просто промойте поток. Закройте его везде, где он был открыт, когда он больше не нужен.