Entradas e Saídas em Java: Difference between revisions

From Wiki**3

Root (talk | contribs)
No edit summary
Root (talk | contribs)
No edit summary
 
(21 intermediate revisions by the same user not shown)
Line 1: Line 1:
{{NAVPO}}
{{TOCright}}
{{TOCright}}
Mecanismos de entradas e saídas em Java. A classe File. Streams, Readers, Writers. Composição de canais. Acesso aleatório a ficheiros. Serialização de tipos primitivos e de objectos: a interface Serializable. Elementos não serializáveis: a palavra chave transient. Excepções associadas a entradas e saí­das.
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.  


== Mecanismos de Entrada e Saída de Dados ==
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).


Mecanismos de entradas e saídas em Java. A classe File. Streams, Readers, Writers. Composição de canais. Acesso aleatório a ficheiros.  
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).


=== Exemplo: Leitor1 ===
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


<java5>
= Nota sobre ordenação de texto em língua natural =
public class Leitor1 {


  public static void main(String[] args) throws IOException {
== 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:
    // Leitura de linhas


    BufferedReader in = new BufferedReader(new FileReader("Leitor1.java"));
  Análise e Síntese de Algoritmos
    String s, s2 = new String();
  Compiladores
    while((s = in.readLine()) != null) s2 += s + "\n";
  Cálculo I
    in.close();
  Álgebra
    System.out.print(s2);


    //------------------------------------------------
A ordem correcta seria:
    // Leitura do System.in (a.k.a. stdin)


    BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
  Álgebra
    System.out.print("Enter a line: ");
  Análise e Síntese de Algoritmos
    System.out.println(stdin.readLine());
  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):
}
</java5>
 
=== Exemplo: Leitor2 ===
 
<java5>
public class Leitor2 {
 
  public static void main(String[] args) throws IOException {
 
    String s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";


    //------------------------------------------------
{{CollapsedCode|Collator & Locale|<source lang="java">
    // Leitura de memória (caracteres Unicode: 16 bits)
import java.text.Collator;
    StringReader strin = new StringReader(s);
import java.util.Locale;
    int c;
import java.util.ArrayList;
    while((c = strin.read()) != -1) System.out.println((char)c);
import java.util.Collections;


    //------------------------------------------------
public class App {
    // Leitura formatada de memória (bytes: 8 bits)
          public static void main(String[] main) {
    try {
                ArrayList<String> l = new ArrayList<>();
 
                l.add("Análise e Síntese de Algoritmos");
      byte ba[] = s.getBytes();
                l.add("Compiladores");
      DataInputStream memin = new DataInputStream(new ByteArrayInputStream(ba));
                l.add("Cálculo I");
      while(true) System.out.print((char)memin.readByte());
                l.add("Álgebra");
 
                Collections.sort(l, Collator.getInstance(Locale.getDefault()));
    }
                System.out.println(l);
    catch(EOFException e) { System.err.println("... já está!"); }
        }
   
  }
}
}
</java5>
</source>
}}


=== Exemplo: Escrita em Ficheiro (Escritor1) ===
== Collators serializáveis ==


<java5>
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.
public class Escritor1 {


  public static void main(String[] args) throws IOException {
{{CollapsedCode|CollatorWrapper.java|<source lang="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;


    try {
class CollatorWrapper implements Comparator<String>, Serializable {
      //String s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  private static final long serialVersionUID = 202110251850L;
      //BufferedReader in = new BufferedReader(new StringReader(s));


      BufferedReader in = new BufferedReader(new FileReader("Escritor1.java"));
   private transient Collator _collator = Collator.getInstance(Locale.getDefault());
 
      PrintWriter   out =
        new PrintWriter(new BufferedWriter(new FileWriter("Escritor1.out")));
 
      int lineCount = 1;
      while((s = in.readLine()) != null ) out.printf("%3d: %s\n", lineCount++, s);
      out.close();
 
    }
    catch(EOFException e) { System.err.println("... já está!"); }


  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); }
}
}
</java5>
</source>
}}


=== Exemplo: Escrita de Leitura Binárias (dados) (Escritor2) ===
Exemplo de aplicação que usa o wrapper.
{{CollapsedCode|App.java|<source lang="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;


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


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


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


      out.writeUTF("Valor de PI");
                try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream("set.dat")))) {
      out.writeDouble(Math.PI);
                  set = (Set<String>)ois.readObject();
      out.writeUTF("Raiz quadrada de 2");
                }
      out.writeDouble(Math.sqrt(2));
                catch (IOException | ClassNotFoundException e) { e.printStackTrace(); }
      out.close();


      DataInputStream in =
                // add more elements
        new DataInputStream(new BufferedInputStream(new FileInputStream("raw.dat")));
                set.add("Cálculo I");
 
                set.add("Álgebra");
      System.out.println(in.readUTF());
      System.out.println(in.readDouble());
      System.out.println(in.readUTF());
      System.out.println(in.readDouble());
 
    }
    catch(EOFException e) { throw new RuntimeException(e); }
 
  }


                System.out.println(set);
        }
}
}
</java5>
</source>
 
}}
=== Exemplo: Leitura e Escrita de Acesso Aleatório ===
 
<java5>
public class LeituraEscritaAleatória {


  public static void main(String[] args) throws IOException {
= Exemplos e Exercícios =
 
== Exemplos ==
    RandomAccessFile rf = new RandomAccessFile("raw.dat", "rw");
* [[Entradas e Saídas em Java/Exemplo 01: Leitura e Escrita de Texto|Exemplo 01: Leitura e Escrita de Texto]]
    for(int i = 0; i < 10; i++) rf.writeDouble(i * 1.414);
* [[Entradas e Saídas em Java/Exemplo 02: Ficheiros de Acesso Binário|Exemplo 02: Ficheiros de Acesso Binário]]
    rf.close();
* [[Entradas e Saídas em Java/Exemplo 03: Ficheiro de Acesso Aleatório|Exemplo 03: Ficheiro de Acesso Aleatório]]
 
* [[Entradas e Saídas em Java/Exemplo 04: Serialização de Objectos|Exemplo 04: Serialização de Objectos]] - Zorg e Zog
    rf = new RandomAccessFile("raw.dat", "rw");
    rf.seek(5*8);
    rf.writeDouble(47.0001);
    rf.close();
 
    rf = new RandomAccessFile("raw.dat", "r");
    for(int i = 0; i < 10; i++)
      System.out.println("Valor " + i + ": " + rf.readDouble());
    rf.close();
 
  }
 
}
</java5>
 
== Serialização de Objectos ==
 
Serialização de tipos primitivos e de objectos: a interface Serializable. Elementos não serializáveis: a palavra chave transient.
 
=== Exemplo: Zorg e Zog ===
 
<java5>
class Alienígena implements Serializable {
  String _nome;
  transient String _segredo = "7";
  public Alienígena(String n) { _nome = n; _segredo = _nome + _nome.length(); }
  public void voing() { System.out.println(_nome + (_segredo != null ? _segredo : "")); }
}
</java5>
 
<java5>
public class Serialização {
  public static void main(String[] args) throws IOException, ClassNotFoundException {
 
    Alienígena a1 = new Alienígena("Zorg"), a2 = new Alienígena("Zog");
    a1.voing();  //output: ZorgZorg4
    a2.voing();  //output: ZogZog3
 
    ObjectOutputStream out =
      new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("raw.dat")));
    out.writeObject(a1); out.writeObject(a2);
    out.close();
 
    ObjectInputStream in =
      new ObjectInputStream(new BufferedInputStream(new FileInputStream("raw.dat")));
    Alienígena r1 = (Alienígena)in.readObject();  // pode lançar “StreamCorruptedException”
    Alienígena r2 = (Alienígena)in.readObject();
    r1.voing();  //output: Zorg
    r2.voing();  //output: Zog
 
  }
}
</java5>


== Exercícios ==
== Exercícios ==
Line 195: Line 131:
* [[Entradas e Saídas em Java/Exercício 02: Leitura de Ficheiro Binário|Exercício 02: Leitura de Ficheiro Binário]]
* [[Entradas e Saídas em Java/Exercício 02: Leitura de Ficheiro Binário|Exercício 02: Leitura de Ficheiro Binário]]
* [[Entradas e Saídas em Java/Exercício 03: Serialização de Objectos|Exercício 03: Serialização de Objectos]]
* [[Entradas e Saídas em Java/Exercício 03: Serialização de Objectos|Exercício 03: Serialização de Objectos]]
* [[Entradas e Saídas em Java/Exercício 04: Registo de Gatos|Exercício 04: Registo de Gatos]]


[[category:Java]]
[[category:Ensino]]
[[category:OOP]]
[[category:PO]]
[[category:Teaching]]

Latest revision as of 09:22, 28 September 2023

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