Когда использовать какой подкласс Writer в Java;общие практики - PullRequest
19 голосов
/ 01 ноября 2010

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

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

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

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

РЕДАКТИРОВАТЬ: Спасибо за ответы всем, я действительно ценю информацию, переданную здесь.Немного прискорбно, что вся вещь 1020 * оказалась в фокусе, это просто означало ее в качестве примера.Мой вопрос в основном касался необходимости и использования всех различных реализаций, что, я думаю, было несколько упомянуто в нескольких ответах.

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

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

Ответы [ 4 ]

9 голосов
/ 01 ноября 2010

Классы 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)
}

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

А затем вам необходимо закрыть низкоуровневый Writer в блоке finally, чтобычто вы не пропускаете ресурсы.

Редактировать :

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

7 голосов
/ 01 ноября 2010

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.

Редактировать:

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

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

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

BufferedWriter writer = Files.newWriter(file, Charsets.UTF_8);
4 голосов
/ 01 ноября 2010

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.Я не знаю, что делает это "неприемлемым".Я почти всегда очень рад принять кодировку по умолчанию.Может быть, если вы используете язык, отличный от английского, это проблема.

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

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

2 голосов
/ 01 ноября 2010

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

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

Редактировать: В сообщении Анона правильно указано использование BufferedWriter между ними и указание кодировки.

...