Подтвердить что ты не робот

Когда использовать подкласс Writer в Java; общие практики

Я всегда немного путался с количеством различных реализаций ввода-вывода в Java, и теперь, когда я полностью застрял в разработке моего проекта, я не торопился читать полезные полезные материалы.

Я понял, что нет дружественного к новичкам сравнения (кроме краткого объяснения в API для класса Writer) между различными подклассами Writer класс. Поэтому я решил, что увожу вопрос, для чего нужны разные подклассы?

Например, я обычно использую FileWriter, завернутый с BufferedWriter для моих выходов в файлы, но меня всегда раздражало то, что нет метода println(), и нужно использовать newLine() каждую вторую строку (чтобы сделать вывод доступным для человека). PrintWriter имеет метод println(), но конструктор, поддерживающий добавление, однако...

Я бы очень признателен, если бы вы могли дать мне свои два цента из вашего опыта или хороший путеводитель/как-то, возможно, наткнулся на вас.

EDIT: Спасибо за ответы всем, я очень ценю информацию, переданную здесь. Немного досадно, что вся вещь append() оказалась в фокусе, это просто означало это как пример. Мой вопрос в основном касался необходимости и использования всех различных реализаций, о которых, как я думаю, несколько упоминалось в нескольких ответах.

Невозможно выбрать один ответ, как принято, поскольку есть три действительно твердых ответа, каждый из которых внес свой вклад в мое понимание проблемы. Мне нужно пойти с Аноном, на этот раз, когда он получил наименьшее количество репутации. (я полагаю, что он новичок в SO). Он ответил, что некоторые из них действительно хорошо сформулированы и заданы 0 вопросов. Хороший вклад я бы сказал, и это стоит поощрять.

Сказав это, ColinD и Jay также предоставили действительно хорошие ответы и указали интересные идеи. Особенно комментарий Jay о Java, автоматически обертывающий BufferedWriter, стоит отметить. Еще раз спасибо, ребята, очень оценили!

4b9b3361

Ответ 1

Классы java.io обычно следуют шаблону Decorator. Итак, в то время как PrintWriter не имеет конкретного конструктора, который вам может понадобиться, он имеет конструктор, который принимает еще один Writer, поэтому вы можете сделать что-то вроде следующего:

FileOutputStream fos = null;
try
{
    fos = new FileOutputStream("foo.txt");
    PrintWriter out = new PrintWriter(
                          new BufferedWriter(
                              new OutputStreamWriter(fos, "UTF-8")));
    // do what you want to do
    out.flush();
    out.close();
}
finally
{
    // quietly close the FileOutputStream (see Jakarta Commons IOUtils)
}

В качестве общего примечания об использовании вы всегда хотите обернуть низкоуровневый Writer (например, FileWriter или OutputStreamWriter) в BufferedWriter, чтобы минимизировать фактические операции ввода-вывода. Однако это означает, что вам нужно явно скрывать и закрывать самого внешнего Writer, чтобы убедиться, что все содержимое записано.

И тогда вам нужно закрыть низкоуровневый Writer в блоке finally, чтобы убедиться, что вы не утечка ресурсов.

Edit

Глядя на ответ MForster, я снова взглянул на API для FileWriter. И я понял, что он не принимает явный набор символов, который является очень плохим. Поэтому я отредактировал фрагмент кода, чтобы использовать FileOutputStream, завернутый в OutputStreamWriter, который принимает явный набор символов.

Ответ 2

FileWriter обычно не является приемлемым классом. Он не позволяет вам указать Charset для записи, что означает, что вы застряли в том, что происходит с кодировкой по умолчанию на платформе, на которой вы работаете. Излишне говорить, что это не позволяет последовательно использовать одну и ту же кодировку для чтения и записи текстовых файлов и может привести к повреждению данных.

Вместо использования FileWriter вы должны обернуть FileOutputStream в OutputStreamWriter. OutputStreamWriter позволяет вам указать кодировку:

File file = ...
OutputStream fileOut = new FileOutputStream(file);
Writer writer = new BufferedWriter(new OutputStreamWriter(fileOut, "UTF-8"));

Чтобы использовать PrintWriter с приведенным выше, просто оберните BufferedWriter в PrintWriter:

PrintWriter printWriter = new PrintWriter(writer);

Вы также можете использовать конструктор PrintWriter, который принимает File и имя кодировки:

PrintWriter printWriter = new PrintWriter(file, "UTF-8");

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

Другие типы Writer в основном предназначены для специализированного использования:

  • StringWriter - это просто Writer, который можно использовать для создания String. CharArrayWriter то же самое для char[].
  • PipedWriter для трубопровода до PipedReader.

Edit:

Я заметил, что вы прокомментировали еще один ответ о многословии создания автора таким образом. Обратите внимание, что существуют библиотеки, такие как Guava, которые помогают уменьшить объемность общих операций. Возьмем, например, запись файла String в файл в определенной кодировке. С Guava вы можете просто написать:

Files.write(text, file, Charsets.UTF_8);

Вы также можете создать BufferedWriter следующим образом:

BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8);

Ответ 3

PrintWriter не имеет конструктора, который принимает параметр "добавить", но FileWriter делает это. И мне кажется логичным, что там, где он принадлежит. PrintWriter не знает, записываете ли вы файл, сокет, консоль, строку и т.д. Что это значит "добавить" к записи в сокет?

Итак, правильный способ сделать то, что вы хотите, просто:

PrintWriter out=new PrintWriter(new BufferedWriter(new FileWriter(myfile, append)));

Интересная заметка: если вы завершаете OutputStream в PrintWriter, Java автоматически добавляет BufferedWriter посередине. Но если вы обернете Writer в PrintWriter, это не так. Поэтому ничего не получается, говоря:

PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(myfile))));

Просто оставьте BufferedWriter и OutputStreamWriter, вы получите их бесплатно в любом случае. Я не знаю, есть ли веские причины для несогласованности.

Верно, что вы не можете указывать кодировку символов в FileWriter как заметки ColinD. Я не знаю, что это делает его "неприемлемым". Я почти всегда с удовольствием принимаю кодировку по умолчанию. Возможно, если вы используете язык, отличный от английского, это проблема.

Необходимость обертывания Writers или OutputStreams в слоях сбивала меня с толку, когда я впервые начал использовать Java. Но как только вы получите это, это не имеет большого значения. Вам просто нужно свести свой ум в рамки записи. У каждого автора есть функция. Подумайте об этом, я хочу напечатать файл, поэтому мне нужно обернуть FileWriter в PrintWriter. Или я хочу преобразовать выходной поток в запись, поэтому мне нужен OutputStreamWriter. Etc.

Или, может быть, вы просто привыкаете к тем, кого используете все время. Объясните это один раз и вспомните, как вы это сделали.

Ответ 4

Вы можете создать добавление PrintWriter следующим образом:

OutputStream os = new FileOutputStream("/tmp/out", true);
PrintWriter writer = new PrintWriter(os);

Изменить: Сообщение анонимного права относительно использования BufferedWriter между ними и указания кодировки.