semaforos productor monitores lectores escritores consumidor java io subclass writer

productor - monitores en java



Cuándo usar qué subclase de escritor en Java; prácticas comunes (4)

Siempre he estado ligeramente confundido con la cantidad de implementaciones de IO diferentes en Java, y ahora que estoy completamente estancado en el desarrollo de mi proyecto, me estaba tomando mi tiempo para leer cosas útiles mientras tanto.

Me he dado cuenta de que no hay una comparación amigable para los principiantes (aparte de una breve explicación en la API para la clase Writer ) entre las diferentes subclases de la clase Writer . Así que pensé que iba a rechazar la pregunta, ¿para qué sirven esas diferentes subclases?

Por ejemplo, generalmente uso un FileWriter envuelto con un BufferedWriter para mis salidas a archivos, pero siempre me ha irritado el hecho de que no haya un método similar a println() , y uno tiene que usar newLine() cada segunda línea (para hacer la salida humana legible). PrintWriter tiene el método println() pero ningún constructor que admita la adición sin embargo ...

Realmente apreciaría si pudieras darme tus dos centavos de tu experiencia, o un buen guía / cómo podría haberte encontrado.

EDIT: Gracias por las respuestas a todos, realmente aprecio la información que se transmite aquí. Es un poco desafortunado que toda la cosa del append() termine en foco, simplemente lo puso como ejemplo. Mi pregunta se refería principalmente a la necesidad y uso de todas las diferentes implementaciones, que supongo que se mencionó un poco en un par de respuestas.

Es difícil elegir una respuesta como aceptada, ya que hay tres respuestas realmente sólidas, cada una ha contribuido a mi comprensión del problema. Voy a tener que irme con Anon, esta vez ya que él tiene la menor cantidad de representantes. puntos (supongo que es nuevo en SO). Tiene 15 respuestas, algunas de las cuales están muy bien formuladas y 0 preguntas. Buena aportación que diría, y que vale la pena promocionar.

Dicho esto, ColinD y Jay también proporcionaron respuestas realmente buenas y señalaron ideas interesantes. Especialmente el comentario de Jay sobre Java envolviendo automáticamente un BufferedWriter fue digno de mención. Gracias de nuevo chicos, realmente apreciado!


Las clases java.io generalmente siguen el patrón de Decorator. Entonces, mientras PrintWriter no tiene el constructor específico que podrías desear, sí tiene un constructor que toma otro Writer , por lo que puedes hacer algo como lo siguiente:

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) }

Como nota de uso general, siempre desea envolver un Writer de bajo nivel (por ejemplo, FileWriter o OutputStreamWriter ) en un BufferedWriter , para minimizar las operaciones reales de IO. Sin embargo, esto significa que debe vaciar y cerrar explícitamente el editor externo para garantizar que todo el contenido esté escrito.

Y luego debe cerrar el Escritor de bajo nivel en un bloque final, para asegurarse de que no pierde recursos.

Editar :

Mirar la respuesta de MForster me hizo echar otro vistazo a la API para FileWriter. Y me di cuenta de que no se necesita un conjunto de caracteres explícito, que es una cosa muy mala. Así que he editado mi fragmento de código para usar un FileOutputStream en un OutputStreamWriter que toma un conjunto de caracteres explícito.


PrintWriter no tiene un constructor que tome un parámetro "anexar", pero FileWriter sí lo tiene. Y me parece lógico que ahí es donde pertenece. PrintWriter no sabe si está escribiendo en un archivo, un socket, la consola, una cadena, etc. ¿Qué significaría "anexar" en las escrituras en un socket?

Así que la forma correcta de hacer lo que quieres es simplemente:

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

Nota interesante: si envuelve un OutputStream en un PrintWriter, Java inserta automáticamente un BufferedWriter en el medio. Pero si envuelve un escritor en un PrintWriter, no lo hace. Así que nada se gana diciendo:

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

Simplemente deje fuera el BufferedWriter y el OutputStreamWriter, de todos modos los obtendrá de forma gratuita. No tengo idea de si hay alguna buena razón para la inconsistencia.

Es cierto que no puede especificar una codificación de caracteres en un FileWriter como notas de ColinD. No sé que eso lo hace "inaceptable". Casi siempre estoy feliz de aceptar la codificación predeterminada. Quizás si estás usando un idioma que no sea inglés, este es un problema.

La necesidad de envolver Writers o OutputStreams en capas me resultó confusa cuando empecé a usar Java. Pero una vez que lo entiendes, no es gran cosa. Solo tienes que inclinar tu mente hacia el marco de escritura. Cada escritor tiene una función. Piense en ello como, quiero imprimir en un archivo, por lo que necesito envolver un FileWriter en un PrintWriter. O, quiero convertir una secuencia de salida en un escritor, por lo que necesito un OutputStreamWriter. Etc.

O tal vez solo te acostumbras a los que usas todo el tiempo. Descúbrelo una vez y recuerda cómo lo hiciste.


Puedes crear un PrintWriter como este:

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

Edición: la publicación de Anon tiene razón sobre el uso de BufferedWriter en el medio y la especificación de la codificación.


FileWriter generalmente no es una clase aceptable para usar. No le permite especificar el Charset de Charset que se usará para la escritura, lo que significa que está atascado con cualquiera que sea el conjunto de caracteres predeterminado de la plataforma en la que se está ejecutando. No hace falta decir que esto hace que sea imposible usar el mismo conjunto de caracteres para leer y escribir archivos de texto de manera consistente y puede llevar a datos dañados.

En lugar de utilizar FileWriter , debe envolver un FileOutputStream en un OutputStreamWriter . OutputStreamWriter le permite especificar un conjunto de caracteres:

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

Para usar PrintWriter con lo anterior, simplemente envuelva el BufferedWriter en un PrintWriter :

PrintWriter printWriter = new PrintWriter(writer);

También puedes usar el constructor PrintWriter que toma un File y el nombre de un conjunto de caracteres:

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

Esto funciona bien para su situación particular, y en realidad hace exactamente lo mismo que el código anterior, pero es bueno saber cómo construirlo envolviendo las distintas partes.

Los otros tipos de Writer son principalmente para usos especializados:

  • StringWriter es solo un Writer que se puede usar para crear una String . CharArrayWriter es el mismo para char[] .
  • PipedWriter para canalizar a un PipedReader .

Editar:

Noté que comentaste otra respuesta sobre la verbosidad de crear un escritor de esta manera. Tenga en cuenta que hay bibliotecas como Guava que ayudan a reducir la verbosidad de las operaciones comunes. Tome, por ejemplo, escribir una String en un archivo en un conjunto de caracteres específico. Con guava solo puedes escribir:

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

También puedes crear un BufferedWriter como este:

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