CodeGym /Blogue Java /Random-PT /Entrada/saída em Java. Classes FileInputStream, FileOutpu...
John Squirrels
Nível 41
San Francisco

Entrada/saída em Java. Classes FileInputStream, FileOutputStream e BufferedInputStream

Publicado no grupo Random-PT
"Oi! Na lição de hoje, continuaremos nossa conversa sobre fluxos de entrada e saída em Java ( Java I/O ). Esta não é a primeira lição sobre este tópico e certamente não será a última Entrada/saída em Java.  Classes FileInputStream, FileOutputStream e BufferedInputStream - 1:) acontecer, a linguagem Java fornece muitas maneiras de trabalhar com E/S. Existem algumas classes que implementam essa funcionalidade, então as dividimos em várias lições — para que você não fique confuso desde o início :) No passado lições, abordamos BufferedReader, bem como as classes abstratas InputStreame OutputStreame vários descendentes. Hoje vamos considerar 3 novas classes: FileInputStream,  FileOutputStream, e  BufferedInputStream.

A classe FileOutputStream

O principal objetivo da FileOutputStreamclasse é gravar bytes em um arquivo. Nada complicado :) FileOutputStreamé uma das implementações da OutputStreamclasse abstrata. No construtor, os objetos dessa classe levam o caminho para o arquivo de destino (onde os bytes devem ser gravados) ou um Fileobjeto. Examinaremos exemplos de cada um:

public class Main { 

   public static void main(String[] args) throws IOException { 

       File file = new File("C:\\Users\\Username\\Desktop\\test.txt"); 
       FileOutputStream fileOutputStream = new FileOutputStream(file); 

       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!"; 

       fileOutputStream.write(greetings.getBytes()); 
       fileOutputStream.close(); 
   } 
}
Ao criar o Fileobjeto, passamos o caminho desejado para o construtor. Não precisamos criá-lo com antecedência: se não existir, o programa o criará. Você também pode passar sem criar um objeto extra, simplesmente passando uma string com o caminho:

public class Main { 

    public static void main(String[] args) throws IOException { 

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt"); 
       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!"; 

       fileOutputStream.write(greetings.getBytes()); 
       fileOutputStream.close(); 
   } 
} 
O resultado em ambos os casos será o mesmo. Podemos abrir nosso arquivo e ver o seguinte:

Hi! Welcome to CodeGym — The best site for would-be programmers!
Mas há uma nuance aqui. Tente executar o código do exemplo acima várias vezes seguidas. Em seguida, olhe no arquivo e responda a esta pergunta: quantas linhas ele tem? Apenas um. Mas você executou o código várias vezes. Acontece que os dados são substituídos todas as vezes - o antigo é substituído pelo novo. O que fazemos se isso não nos convém e precisamos escrever sequencialmente no arquivo? E se quisermos escrever nossa saudação em um arquivo três vezes seguidas? É tudo muito simples. Como a linguagem não pode saber qual comportamento precisamos em cada caso, o FileOutputStreamconstrutor pode receber um parâmetro adicional —boolean append. Se seu valor for true, os dados serão gravados no final do arquivo. Se for falso (e por padrão é falso), todos os dados antigos serão apagados e substituídos por novos dados. Vamos verificar isso executando nosso código modificado três vezes:

public class Main { 

   public static void main(String[] args) throws IOException { 

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true); 
       String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n"; 

       fileOutputStream.write(greetings.getBytes()); 
       fileOutputStream.close(); 
   } 
} 
Conteúdo do arquivo:

Hi! Welcome to CodeGym — The best site for would-be programmers! 
Hi! Welcome to CodeGym — The best site for would-be programmers! 
Hi! Welcome to CodeGym — The best site for would-be programmers!
Agora isso é diferente! Não se esqueça desse recurso ao usar classes de E/S. Houve um tempo em que eu passava horas em tarefas, quebrando a cabeça por horas, tentando entender como meus dados estavam desaparecendo dos arquivos :) E claro, assim como em outras classes de I/O, não se esqueça de usar o close()método para liberar recursos.

A classe FileInputStream

O FileInputStreamtem o propósito oposto - ler bytes de um arquivo. Assim como FileOutputStreama herança OutputStream, esta classe deriva da InputStreamclasse abstrata. Escreveremos algumas linhas de texto em nosso arquivo " test.txt ":

"So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters"
Entrada/saída em Java.  Classes FileInputStream, FileOutputStream e BufferedInputStream - 2Veja como é ler dados de um arquivo usando FileInputStream:

public class Main { 

   public static void main(String[] args) throws IOException { 

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt"); 

       int i; 

       while((i=fileInputStream.read())!= -1){ 

           System.out.print((char)i); 

       } 
   } 
}
Lemos um byte do arquivo, convertemos os bytes lidos em caracteres e os exibimos no console. E aqui está a saída do console:

So close no matter how far 
Couldn't be much more from the heart 
Forever trusting who we are 
And nothing else matters

A classe BufferedInputStream

Eu acho que, dado o conhecimento das lições anteriores, você pode facilmente dizer por que precisamos da BufferedInputStreamaula e quais vantagens ela tem em comparação com FileInputStream:) Já encontramos fluxos em buffer, então tente adivinhar (ou lembre-se) antes de continuar lendo :) Fluxos com buffer são necessários principalmente para otimizar a E/S. Acessar uma fonte de dados, como a leitura de um arquivo, é uma operação cara em termos de desempenho. E acessar um arquivo para ler cada byte é um desperdício. É por isso que BufferedInputStreamlê os dados não um byte por vez, mas em blocos e os armazena temporariamente em um buffer especial. Isso nos permite otimizar o programa reduzindo o número de vezes que acessamos o arquivo. Vamos ver como isso se parece:

public class Main { 

   public static void main(String[] args) throws IOException { 

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt"); 

       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200); 

       int i; 

       while((i = bufferedInputStream.read())!= -1){ 

           System.out.print((char)i); 
       } 
   } 
} 
Aqui criamos um BufferedInputStreamobjeto. Seu construtor pega uma instância da InputStreamclasse ou qualquer um de seus descendentes, então FileInputStreamo fará. Como argumento adicional, considera o tamanho do buffer em bytes. Graças a este argumento, os dados agora serão lidos do arquivo não um byte por vez, mas 200 bytes por vez! Imagine o quanto reduzimos o número de acessos a arquivos. Para comparar o desempenho, você pode pegar um arquivo de texto grande (vários megabytes de texto) e comparar quanto tempo leva em milissegundos para ler e enviar para o console usando FileInputStreame BufferedInputStream. Aqui está o código que demonstra ambas as opções:

public class Main { 

   public static void main(String[] args) throws IOException { 

       Date date = new Date(); 

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf"); 
       BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream); 

       int i; 
       while((i = bufferedInputStream.read())!= -1){ 

           System.out.print((char)i); 
       } 

       Date date1 = new Date(); 
       System.out.println((date1.getTime() - date.getTime())); 
   } 
} 

 
public class Main { 

   public static void main(String[] args) throws IOException { 

       Date date = new Date(); 
       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf"); 

       int i; 
       while((i = fileInputStream.read())!= -1){ 

           System.out.print((char)i); 
       } 


       Date date1 = new Date(); 
       System.out.println((date1.getTime() - date.getTime())); 
   }
}
Ao ler um arquivo de 1,5 MB no meu computador, FileInputStreamconcluí o trabalho em ~ 3.500 milissegundos, mas BufferedInputStreamo gerenciei em ~ 1.700 milissegundos. Como você pode ver, o fluxo em buffer otimizou o trabalho, cortando-o pela metade! :) Continuaremos a estudar as aulas de I/O — até breve!
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION