DataOutputStream#writeBytes(String) против BufferedWriter#write(String)

Я хочу создать HTML-файл для своего отчета. Содержимое отчета может быть создано с помощью BufferedWriter#write(String)

File f = new File("source.htm");
BufferedWriter bw = new BufferedWriter(new FileWriter(f));
bw.write("Content");

или с помощью DataOutputStream#writeBytes(String)

File f = new File("source.htm");
DataOutputStream dosReport = new DataOutputStream(new FileOutputStream(f)); 
dosReport.wrtiteBytes("Content");

Один из них лучше другого? Почему это так?


person Java Beginner    schedule 03.12.2013    source источник
comment
возможный дубликат Writer или OutputStream?   -  person Joachim Sauer    schedule 03.12.2013
comment
Рассмотрите возможность использования нового файлового API NIO.2.   -  person Puce    schedule 03.12.2013
comment
@Puce Подумайте, почему?   -  person user207421    schedule 04.12.2013
comment
@EJP java.io.File считается устаревшим API в Java SE 7. docs.oracle.com/javase/tutorial/essential/io/legacy.html   -  person Puce    schedule 04.12.2013


Ответы (3)


Если вы пишете текст, вам следует использовать Writer, который обрабатывает преобразование из символов Юникода (внутреннее представление строк в Java) в соответствующую кодировку символов, такую ​​как UTF-8. DataOutputStream.writeBytes просто выводит младшие восемь бит каждого char в строке и полностью игнорирует старшие восемь бит - это эквивалентно UTF-8 для символов ASCII с кодами ниже 128 (U+007F и ниже), но почти наверняка неверно для всего, кроме ASCII.

Вместо FileWriter вы должны использовать OutputStreamWriter, чтобы вы могли выбрать конкретную кодировку (FileWriter всегда использует кодировку платформы по умолчанию, которая варьируется от платформы к платформе):

File f = new File("source.htm");
BufferedWriter bw = new BufferedWriter(
  new OutputStreamWriter(new FileOutputStream(f), "UTF-8"));
bw.write("Content");
person Ian Roberts    schedule 03.12.2013

Во-первых, DataOutputStream в вашем втором примере не служит никакой полезной цели1. Действительно, если ваши строки содержат символы, которые не помещаются в 8 бит, метод writeBytes(String) исказит текст. Избавиться от этого. Потоки данных предназначены для чтения и записи мелкозернистых двоичных данных. Для простых байтов используйте простой (или буферизованный) поток ввода или вывода.

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

Так и в этом случае. вы должны сравнивать:

    File f = new File("source.htm");
    Writer w = new FileWriter(f);
    w.write("Content");

против

    File f = new File("source.htm");
    OutputStream os = new FileOutputStream(f); 
    os.write("Content".getBytes());

На мой взгляд, первая версия выглядит проще и чище. И лучше всего использовать стеки Reader и Writer для текстового ввода-вывода... потому что именно для этого они были разработаны. (Они заботятся о вопросах кодирования и декодирования, чисто и прозрачно.)

Вы можете сравнить их, если вам действительно нужно знать, что быстрее (в вашей системе!), но я подозреваю, что большой разницы нет ... и что первая версия быстрее.

1. Я думаю, что в DataOutputStream скрыта буферизация, но в данном случае буферизация не способствует повышению производительности.


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


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

person Stephen C    schedule 03.12.2013

Выходной поток:

Этот абстрактный класс является надклассом всех классов, представляющих выходной поток байтов. Выходной поток принимает выходные байты и отправляет их в некоторый приемник.

Приложения, которым необходимо определить подкласс OutputStream, всегда должны предоставлять как минимум метод, записывающий один байт вывода.

Например:

OutputStream os = new FileOutputStream("test.txt");

BufferedWriter

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

Предоставляется метод newLine(), который использует собственное понятие разделителя строк платформы, определенное системным свойством line.separator. Не все платформы используют символ новой строки ('\n') для завершения строки. Поэтому вызов этого метода для завершения каждой строки вывода предпочтительнее, чем запись символа новой строки напрямую.

Как правило, Writer немедленно отправляет свой вывод в базовый поток символов или байтов. Если не требуется оперативный вывод, рекомендуется обернуть BufferedWriter любой Writer, чьи write() операции могут быть дорогостоящими, например FileWriters и OutputStreamWriters.

Например:

 PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
person Sanjay Nagare    schedule 03.12.2013
comment
Прямая цитата из JavaDocs без указания авторства или дальнейшего обсуждения не является ответом... - person Ian Roberts; 03.12.2013