Entradas e Saídas em Java

From Wiki**3

Programação com Objectos
Introduction
Creation and Destruction
Inheritance & Composition
Abstraction & Polymorphism
Code Organization
Java Topics
Inner Classes
Enumerations
Data Structures
Exceptions
Input/Output
RTTI
Other Topics
JUnit Tests
UML Topics
Design Patterns
"Simple" Factory
Composite & Visitor
Command
Strategy & State
Template Method
Observer
Abstract Factory
Decorator & Adapter
Façade (aka Facade)

Em Java, tal como noutras linguagens, os mecanismos de entradas e saídas desempenham um papel crucial na manipulação de dados. A classe File é um dos pilares dessa interação, servindo como uma ponte entre o código e os ficheiros no sistema. Para um fluxo mais refinado de dados, existem os conceitos InputStream e OutputStream, por um lado, e Reader e Writer, por outro, que facilitam a leitura e escrita de informação sob várias formas. A composição de canais amplia ainda mais as possibilidades de manipulação de dados. Para estes casos, os padrões de desenho Decorator e Adapter fornecem a estruturação de base.

Existem várias formas pré-definidas de acesso a ficheiros, podendo ser desenvolvidas outras. Uma característica interessante é o acesso aleatório a ficheiros, que permite uma interação não sequencial com os dados persistentes. A serialização, por sua vez, é fundamental para a conversão de tipos primitivos e objectos em formatos armazenáveis, com a interface Serializable desempenhando um papel central. A serialização em Java, através desta interface, é completamente automática. No entanto, como nem tudo é necessariamente serializável, existe a palavra-chave transient para controlar o processo de serialização. Note-se que este processo, apesar de automático e conveniente, tem alguns problemas sérios em alguns contextos. Ver o manual (endereço abaixo).

O controlo de problemas relacionados com entradas e saídas em Java é realizado primariamente via tratamento de excepções. As excepções específicas destas operações são subclasses de IOException (embora possam ocorrer outras, específicas de certas operações).

O manual de Java apresenta uma introdução à package java.io, onde estão organizados estes e outros conceitos. https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/io/package-summary.html

Nota sobre ordenação de texto em língua natural

O "problema" do texto em língua natural

Embora não directamente relacionado com o tópico de entradas e saídas, o processamento de texto pode implicar ordenação de texto em língua natural.

Se forem usados os processos meramente relacionados com a codificação de caracteres, listas de nomes com acentos podem ser ordenadas de forma errónea:

 Análise e Síntese de Algoritmos
 Compiladores
 Cálculo I
 Álgebra

A ordem correcta seria:

 Álgebra
 Análise e Síntese de Algoritmos
 Cálculo I
 Compiladores

A resolução do problema passa pela utilização dos conceitos relacionados com texto e sensíveis às definições de localização (região e língua natural) e não meramente com codificação de caracteres. No caso concreto deste exemplo, usa-se um comparador especial, Collator, parametrizado com uma instância de Locale (define a forma de ordenação para uma dada língua natural):

Collator & Locale
import java.text.Collator;
import java.util.Locale;
import java.util.ArrayList;
import java.util.Collections;

public class App {
          public static void main(String[] main) {
                ArrayList<String> l = new ArrayList<>();
                l.add("Análise e Síntese de Algoritmos");
                l.add("Compiladores");
                l.add("Cálculo I");
                l.add("Álgebra");
                Collections.sort(l, Collator.getInstance(Locale.getDefault()));
                System.out.println(l);
        }
}

Collators serializáveis

Se o objecto que usa o Collator implementar Serializable, pode ocorrer um problema: Collator não implementa Serializable. Uma solução passa por definir um wrapper que é serializável e que reinicializa o Collator quando lido de disco.

CollatorWrapper.java
import java.text.Collator;
import java.util.Comparator;
import java.util.Locale;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;

class CollatorWrapper implements Comparator<String>, Serializable {
  private static final long serialVersionUID = 202110251850L;

  private transient Collator _collator = Collator.getInstance(Locale.getDefault());

  private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    _collator = Collator.getInstance(Locale.getDefault());
  }

  @Override
  public int compare(String s1, String s2) { return _collator.compare(s1, s2); }
}

Exemplo de aplicação que usa o wrapper.

App.java
import java.util.Set;
import java.util.TreeSet;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class App {
          public static void main(String[] main) {
                Set<String> set = new TreeSet<>(new CollatorWrapper());

                // add first two elements
                set.add("Análise e Síntese de Algoritmos");
                set.add("Compiladores");

                try (ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("set.dat")))) {
                  oos.writeObject(set);
                }
                catch (IOException e) { e.printStackTrace(); }

                try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("set.dat")))) {
                  set = (Set<String>)ois.readObject();
                }
                catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }

                // add more elements
                set.add("Cálculo I");
                set.add("Álgebra");

                System.out.println(set);
        }
}

Exemplos e Exercícios

Exemplos

Exercícios