Problema com a leitura de arquivos pelo java [Resolvido]

20 respostas
A

Bom...
Eis que sou um aspirante a programador em java, e quando estava a criar um programa (uma coisa boba... só pra treinar o uso das classes de leitura e escrita de arquivos), eu me deparei com o seguinte problema:

primeiro, meu código:

import java.io.*;
public class Main {
	
	public static void main (String[] args)throws IOException{
	
		BufferedReader arquivo = new BufferedReader(new FileReader("lista de nomes.txt"));
		String nomes = arquivo.readLine();
		
		 while(nomes != null){
			 if (nomes == "João"){
				 System.out.println("ok");
			 }
			 nomes =  arquivo.readLine();
		 }
	}
}

o problema éra que no:

if (nomes == "João"){

o programa "dizia" que nao havia encontrado o nome "João" no arquivo que eu mandei ele ler (embora o arquivo que eu mandei ele ler seja uma lista de nomes, que entre estes está o nome "João" em uma linha separada).

Pois bem, mexo aqui.. mexo ali.. na tentativa de fazer o código funcionar e eis que quando troko aquela linha por:

if (nomes.contains("João") == true){

E problema resolvido...
porém... ficou a dúvida..

Porque isso aconteceu ??

Já que tecnicamente o método "readLine()" retorna uma String, que eu armazenei em uma String, a comparação que eu fiz inicialmente deveria ser válida. Não consegui achar uma explicação para o que aconteceu ali.

Eu até poderia decorar de sempre usar o método "contains" quandu for fazer algo do tipo, mas eu realmente gostaria de saber o porque daquilo ali.

Aproveitando que o topico está falando de leitura de arquivos...

Eu estou aprendendo a ler/escrever arquivos em java , usando o BufferedReader/Writer, passando como parâmetro um FileReader/Writer.

Pesquisando pela internet a fora descobri que há também as classes "Scanner" e "PrintStream" que já seria uma "união" dessas classes("File/BufferedReader" e "File/BufferedWriter"), e mas recentemente me falaram da classe "RandomAccessFile" que já faria a função de ler e escrever arquivos ela mesma.

Eu gostaria de saber se é realmente isso, ou cada uma tem uma função diferente da outra ? Há alguma diferença entre o uso de cada uma ?

E se por acaso for só essa questão de "simplificar" o acesso a arquivos, seria uma perda de tempo usar o "BufferedReader/Writer" podendo usar o "RandomAccessFile" ??

Como eu disse ali em cima eu estou começando em java agora, e estou estudando por conta própria (incrível o quando se pode aprender pela internet), porem isso faz com que eu não tenha um professor pra tirar dúvidas, por isso recorri aqui ao pessoal do forum para esclarecer isso ae.

PS: O post ficou meio grande né xD

PS²: O código ali em cima e uma versão mais simples do problema que eu tive quando eu estava fazendo o meu programa, eu criei aquele código só para ilustrar melhor nesse post o meu problema.

20 Respostas

D

para vc comparar String, compara com equals…
vlw

A

Damiao Cunha:
para vc comparar String, compara com equals…
vlw

Mas por exemplo:

public class Main { public static void main (String[] args){ String var1 = "teste"; String var2 = "teste"; if (var1 == var2){ System.out.println("ok"); } } }

Roda tranquilo, mesmo eu não usandu o método “equals” para comparar.
Pra min no caso ali em cima sería algo assim também, já que o retorno do método “readLine()” é uma String, e eu comparei com outra String.

D

aki vc tá comparando duas variaveis… e lá uma variavel e uma string…
intendeu a diferença…
só não sei te explicar como o compilador entende essa diferença…
vlw

romarcio

Da mesma, tanto comparar

String nome = "João";

if (nome == "João") 
//ou
if (nome.equals(nome))
//ou
if (nome.equals("João"))

ambos serão verdadeiros.

O que daria falso seria compara objetos

String nome = "João";

        Pessoa fulano = new Pessoa();
        fulano.setName("João");

        Pessoa ciclano = new Pessoa();
        ciclano.setName("João");

if (fulano.getName() == ciclano.getName()) true
if (fulano.equals(ciclano)) false //a não ser que vc gere o método equals() and hashcode() da classe Pessoa()
if (fulano.equals(ciclano.getName()))  false
if (fulano.getName().equals(nome) && fulano.getName() == nome && fulano.getName() == "João" && nome == "João")  true
davidbuzatto

CUIDADO! romarcio, olha o que vc postou... Não tanto faz não!

Quando for comparar Strings, utilize SEMPRE o método equals.

alexD, olhe o exemplo

String s1 = "João";
String s2 = new String( "João" );

// true
System.out.println( s1 == "João" );

// false
System.out.println( s2 == "João" );

// false
System.out.println( s1 == s2 );

// todos true
System.out.println( s1.equals( "João" ) );
System.out.println( s2.equals( "João" ) );
System.out.println( s1.equals( s2 ) );

Na linha 01 é criada uma String (usando o literal para String) e a referência para a String criada é associada à variável s1.
Na linha 02 é criada uma outra String, agora usando o construtor de String, e o novo objeto é associado a variável s2.
Na linha 05 a referência de s1 é comparada com a referência da String "João". Note que novamente foi usado o literal para a String. Quando se trabalha com Strings dessa forma, o Java utiliza um pool de Strings. Como "João" já existe e é o mesmo objeto referenciado por s1, o resultado é true, pois tanto s1 quanto "João" apontam para o mesmo objeto.
Na linha 08, compara-se s2 com "João" (o mesmo objeto desde a linha 01). Note que s2 é outro objeto String (pq não foi usado o literal, e sim o construtor), então cada referência aponta para lugares distintos, retornando false.
Na linha 11, ocorre a mesma coisa que ocorreu na linha 08. s1 aponta para a String "João" que está no pool, enquando s2 aponta para a String que não está no pool. Sendo assim, retorna false.

Veja que em todas as tentativas de comparação das Strings usando o método equals (linha 12 em diante), todos os resultados são true, pq usando o método equals vc não está verificando se os dois operandos referenciam o mesmo objeto (o que acontece com o operador ==), mas sim, está verificando se o "conteúdo" de dois objetos é o mesmo.

Caso eu não me tenha feito entender (é o sono :D ), segue a string de pesquisa do google:
http://www.google.com.br/search?hl=pt-BR&rlz=1B3GGLL_pt-BRBR376BR376&q=java+string+pool&aq=f&aqi=&aql=&oq=&gs_rfai=

P.S. aqui tem uma discussão gigantesca em relação ao poool de Strings. No final o ViniGodoy e o thingol dão o ultimato haha. Concordo com eles. Use equals e ponto. Fim de papo. == para primitivos, equals p/ objetos. Pronto.

[]´s

A
Damiao Cunha:
aki vc tá comparando duas variaveis... e lá uma variavel e uma string... intendeu a diferença... só não sei te explicar como o compilador entende essa diferença... vlw

Ainda não intendi...

Fiz mais um teste aqui para se aproximar mais da situação do meu 1º post.

Criei a classe Nomes:

public class Nomes {
	
	private String nome;
	
	public String getNome(){
		return this.nome;
	}
	
	public void setNome(String nome){
		this.nome= nome;
	}

}

Depois na minha classe principal...

public class Main {
	public static void main (String[] args){
		Nomes teste = new Nomes();
		 teste.setNome("João");
		 
		 if (teste.getNome() == "João"){
			 System.out.println("ok");
		 }
		
	}
}

No caso o método "getNome" desse meu exemplo sería o equivalente ao "readLine()" do meu 1º post, e assim como lá em cima, eu comparo ele diretamente com um texto (sem passar o texto para uma variavel String).

E o código roda certinho (eu obtenho a msg "ok" no console) o que aumenta mais ainda minha dúvida...

Edit
--------------------
@ davidbuzatto

Intendi bem o que você disse, já tinha lido algo a respeito desse "lance" com Strings, mas como ate agora eu só usava minhas próprias Strings, e sempre usava elas nesse estilo "variavel" em vez de instanciar e talz, então eu sempre comparava com o "==" e rodava certo.

fiz mais uns testes aqui pra intender melhor e quando troquei o método "setNome" da minha classe Nomes para:

public void setNome(String nome){
		this.nome = new String(nome);
	}

a comparação que eu tinha feito com "==" na minha classe Main deu o mesmo problema que eu tive lá em cima, e quando usei o "equals" tudo rodou certo.

Imagino que seja algo assim quando uso as classes da API (as "Strings" delas sempre nesse esquema de instância), mas como esse e o meu primero contato com as classes da API eu não sabia disso xD

Apartir de agora vou seguir o conselho e sempre comparar com o "equals" e deixar o "==" para os tipos primitivos...

vlw a ajuda ae :D

Ps: O Edit porque quando eu fiz esse post o seu ainda não tava ali e talz... sabe como é né.. xD

Ps² Aproveitando que essa dúvida foi sanada, agora só queria uma resposta pra minha outra pergunta la no 1º post:

Pesquisando pela internet a fora descobri que há também as classes "Scanner" e "PrintStream" que já seria uma "união" dessas classes("File/BufferedReader" e "File/BufferedWriter"), e mas recentemente me falaram da classe "RandomAccessFile" que já faria a função de ler e escrever arquivos ela mesma.

Eu gostaria de saber se é realmente isso, ou cada uma tem uma função diferente da outra ? Há alguma diferença entre o uso de cada uma ?

E se por acaso for só essa questão de "simplificar" o acesso a arquivos, seria uma perda de tempo usar o "BufferedReader/Writer" podendo usar o "RandomAccessFile" ??

davidbuzatto

Minha nossa, não faça isso!

public void setNome(String nome){ this.nome = new String(nome); }

Simplesmente não há necessidade! Vc está intanciando uma nova String a toa.
Use o método equals. O == é p/ comprar o valor de primitivos ou se duas referências apontam para o mesmo objeto.
Acho que seu código acima foi só para testes não é?

[]´s

A

davidbuzatto:
Minha nossa, não faça isso!

public void setNome(String nome){ this.nome = new String(nome); }

Simplesmente não há necessidade! Vc está intanciando uma nova String a toa.
Use o método equals. O == é p/ comprar o valor de primitivos ou se duas referências apontam para o mesmo objeto.
Acho que seu código acima foi só para testes não é?

[]´s

Sim, esse código foi só pra provar a minha “teoría” do porque no exemplo que eu dei ai em cima (antes do edit), eu tinha conseguido o resultado no console usando o “==”, e la no meu primero post quando eu uso o método “readLine()” da classe “BufferedReader”, eu não consegui o resultado que eu queria usando o “==” :stuck_out_tongue:

romarcio
davidbuzatto:
CUIDADO! romarcio, olha o que vc postou... Não tanto faz não!

Quando for comparar Strings, utilize SEMPRE o método equals.

alexD, olhe o exemplo

String s1 = "João";
String s2 = new String( "João" );

// true
System.out.println( s1 == "João" );

// false
System.out.println( s2 == "João" );

// false
System.out.println( s1 == s2 );

// todos true
System.out.println( s1.equals( "João" ) );
System.out.println( s2.equals( "João" ) );
System.out.println( s1.equals( s2 ) );

Na linha 01 é criada uma String (usando o literal para String) e a referência para a String criada é associada à variável s1.
Na linha 02 é criada uma outra String, agora usando o construtor de String, e o novo objeto é associado a variável s2.
Na linha 05 a referência de s1 é comparada com a referência da String "João". Note que novamente foi usado o literal para a String. Quando se trabalha com Strings dessa forma, o Java utiliza um pool de Strings. Como "João" já existe e é o mesmo objeto referenciado por s1, o resultado é true, pois tanto s1 quanto "João" apontam para o mesmo objeto.
Na linha 08, compara-se s2 com "João" (o mesmo objeto desde a linha 01). Note que s2 é outro objeto String (pq não foi usado o literal, e sim o construtor), então cada referência aponta para lugares distintos, retornando false.
Na linha 11, ocorre a mesma coisa que ocorreu na linha 08. s1 aponta para a String "João" que está no pool, enquando s2 aponta para a String que não está no pool. Sendo assim, retorna false.

Veja que em todas as tentativas de comparação das Strings usando o método equals (linha 12 em diante), todos os resultados são true, pq usando o método equals vc não está verificando se os dois operandos referenciam o mesmo objeto (o que acontece com o operador ==), mas sim, está verificando se o "conteúdo" de dois objetos é o mesmo.

Caso eu não me tenha feito entender (é o sono :D ), segue a string de pesquisa do google:
http://www.google.com.br/search?hl=pt-BR&rlz=1B3GGLL_pt-BRBR376BR376&q=java+string+pool&aq=f&aqi=&aql=&oq=&gs_rfai=

P.S. aqui tem uma discussão gigantesca em relação ao poool de Strings. No final o ViniGodoy e o thingol dão o ultimato haha. Concordo com eles. Use equals e ponto. Fim de papo. == para primitivos, equals p/ objetos. Pronto.

[]´s

Valeu pela observação. Eu não tinha levado em conta o caso criado para s2.

M

alexD:
Bom…

o problema éra que no:

if (nomes == "João"){

o programa “dizia” que nao havia encontrado o nome “João” no arquivo que eu mandei ele ler (embora o arquivo que eu mandei ele ler seja uma lista de nomes, que entre estes está o nome “João” em uma linha separada).

Pois bem, mexo aqui… mexo ali… na tentativa de fazer o código funcionar e eis que quando troko aquela linha por:

if (nomes.contains("João") == true){

E problema resolvido…
porém… ficou a dúvida…

Porque isso aconteceu ??

Isso aconteceu pq uma linha lida do arquivo através do readLine não vêm apenas a String… mas vem tbm o “enter” (separação de linhas), quando vc tentou fazer a comparação a variavel nomes continha, por exemplo, “João/n” e “João” é diferente de “João/n”

MAS “João/n” contem a string “João”

Sacou? :smiley:

A

MaxVenom:
alexD:
Bom…

o problema éra que no:

if (nomes == "João"){

o programa “dizia” que nao havia encontrado o nome “João” no arquivo que eu mandei ele ler (embora o arquivo que eu mandei ele ler seja uma lista de nomes, que entre estes está o nome “João” em uma linha separada).

Pois bem, mexo aqui… mexo ali… na tentativa de fazer o código funcionar e eis que quando troko aquela linha por:

if (nomes.contains("João") == true){

E problema resolvido…
porém… ficou a dúvida…

Porque isso aconteceu ??

Isso aconteceu pq uma linha lida do arquivo através do readLine não vêm apenas a String… mas vem tbm o “enter” (separação de linhas), quando vc tentou fazer a comparação a variavel nomes continha, por exemplo, “João/n” e “João” é diferente de “João/n”

MAS “João/n” contem a string “João”

Sacou? :smiley:

Agora bateu a duvida de novo…

Tudo bem, isso explica o que aconteceu ali.

Porem… depois de toda as respostas que eu tive aqui no tópico, mudei o meu código, troquei o “contains” por “equals” e funcionou tudo perfeito…

Mas se acontece isso que você disse, do retorno do método “readLine()” retornar algo mais do que simplesmente o que está na linha do arquivo (no caso esse “enter”), o “equals” não deveria ter funcionado, já que o retorno do método “readLine()” não sería exatamente o mesmo da string que eu comparei (o “João”)

Isso que voltou a me confundir…

Ps: O pessoal meio que ignorou a minha segunda duvida no 1º post… :frowning:

Pesquisando pela internet a fora descobri que há também as classes “Scanner” e “PrintStream” que já seria uma “união” dessas classes(“File/BufferedReader” e “File/BufferedWriter”), e mas recentemente me falaram da classe “RandomAccessFile” que já faria a função de ler e escrever arquivos ela mesma.

Eu gostaria de saber se é realmente isso, ou cada uma tem uma função diferente da outra ? Há alguma diferença entre o uso de cada uma ?

E se por acaso for só essa questão de “simplificar” o acesso a arquivos, seria uma perda de tempo usar o “BufferedReader/Writer” podendo usar o “RandomAccessFile” ??

romarcio

É que vc tem que ver o que deseja, saber se sua variavel nome é igual a string “João” ou se ela contém a string “João”.

No caso do equals, vc testará se o conteudo dela é “João”, no caso se tiver nela “João Carlos”, nunca será true para equals(“João”).

Mas se vc precisa saber se nessa variavel contém a palavra “João”, dai deve usar o contains, caso ela tenha o conteudo “João Carlos” e você usar o contains(“João”) , o retorno será true.

Vai de acordo com a sua necessidade.

A

romarcio:
É que vc tem que ver o que deseja, saber se sua variavel nome é igual a string “João” ou se ela contém a string “João”.

No caso do equals, vc testará se o conteudo dela é “João”, no caso se tiver nela “João Carlos”, nunca será true para equals(“João”).

Mas se vc precisa saber se nessa variavel contém a palavra “João”, dai deve usar o contains, caso ela tenha o conteudo “João Carlos” e você usar o contains(“João”) , o retorno será true.

Vai de acordo com a sua necessidade.

Entendo, o fato é que eu usei o “contains” ali como uma alternativa ao “==” (pois o '==" não estava fazendo o que eu queria, e eu ainda não sabia a diferença de usar “==” e “equals” na String), depois que me explicaram tudo, eu percebi que o método que eu queria no meu código era o “equals” mesmo.

Porem, o que me confundindo no post do MaxVenom é que ele disse que o “==” não funcionou (la no meu primeiro código) porque o retorno do método “readLine()” (quando está lendo a linha que continha o nome “João”) não era só “João”, mas sim “João” e uma espécie de “enter”

Eu não intendi isso, pois se é esse o caso, porque o “equals” funcionou ?

romarcio

O que ele quiz dizer é que quando vc leu a linha onde tinha a string “João”, essa linha veio com um espaço depois da palavra João.

Tipo como se ficasse assim: "João ", com um espaço no final, esse espaço se dá por causa do clique na tecla enter, quando vc digira uma palavra pela linha de comando.

No seu caso, como está lendo do arquivo, verifica se no seu arquivo não existe esse espaço logo depois da palavra. Se ele existir, vai vir junto quado vc carregar a variavel nome, então seu equals ira procurar por “João” e encontrara "João ", dai vai dizer que é falso. Porém nesse caso, o contains funciona.

Se tiver um espaço em branco como falei, vc pode tentar usar o nome.trim().equals("João") o .trim() vai eliminar o espaço no final da palavra.

adriano_si

Cara… o contains retornou true porque o retorno da sua linha era uma String “Joao”… Logo (“Joao” contem “Joao” ?) resposta TRUE… Esquece isso de “Joao\n” o \n e um caractere de Scape para Strings Java que quebra a linha, ma eh a unica funcao desse cara… quando trouxeres uma linha de um arquivo, vais trazer so o conteudo dessa linha e nao o \n.

Cuidado ao trampar com String, eh um tema bem traicoeiro, mas depois que entendes… Bau Bau…

Precisas entender que a VM cria uma Especie de Heap separado so para Strings. O metodo equals vai sempre comparar o que esta definido como valor de comparacao na classe em questao e na classe String, esse valor e a propria String… Essa imagem abaixo vai te ajudar a entender melhor…

Quando usas o equals vais comparar o valor, usando == vais comparar a referencia…

A

Vocês não estão me entendendo… xD

Eu já sakei bem esse lance da diferença entre usar o “==” e o “equals” com Strings, e o lance do String x = “texto” e String x = new String(“texto”) ( mais valeu pela imagem adriano_si, deu uma compreensão melhor de como funciona)

O fato é que:

Eu quero saber se o código:

if (nomes == "João"){

(lembrando que “nomes” recebeu o “readLine()”)

Não fez o que eu esperava (achar o nome “João” na lista) porque…

… ou se foi porque…

O que ele quiz dizer é que quando vc leu a linha onde tinha a string “João”, essa linha veio com um espaço depois da palavra João.

Tipo como se ficasse assim: "João ", com um espaço no final, esse espaço se dá por causa do clique na tecla enter, quando vc digira uma palavra pela linha de comando.

É só isso que ainda me confunde xD

davidbuzatto

Essa é a certa.

Os espaços e os pulos de linha serão REMOVIDOS dos tokens, afinal, são eles que são usados como separador. Não teria sentido colocá-los em cada token.
Esse tópico já está virando uma novela.

Convenhamos, é só direcionar o token para a saída com um print() para ver se o pulo de linha foi ou não foi junto com o token.

[]´s

A

Hum… acho que isso encerra o assunto (já que eu perdi as esperanças que alguem vá responder a 2ª duvida que eu coloquei la no 1º post).

Fica um obrigado a todo para mundo que veio aqui tirar minha duvida o/

E foi mal sobre isso de o topico virar novela, mas quando falaram desse lance de que o resultado do método poderia vir com um espaço a mais ou algo assim, me confundiu um poco.

De novo… vlw ae pessoal…

E já podem fechar o topico :smiley:

davidbuzatto

alexD:
Hum… acho que isso encerra o assunto (já que eu perdi as esperanças que alguem vá responder a 2ª duvida que eu coloquei la no 1º post).

Fica um obrigado a todo para mundo que veio aqui tirar minha duvida o/

E foi mal sobre isso de o topico virar novela, mas quando falaram desse lance de que o resultado do método poderia vir com um espaço a mais ou algo assim, me confundiu um poco.

De novo… vlw ae pessoal…

E já podem fechar o topico :smiley:

Então Alex, vc misturou um monte de coisa no seu primeiro post e eu acabei não lendo inteiro. Enfim, para facilitar a leitura de arquivos de texto vc pode usar a classe Scanner sim. Sem nenhum problema. A RandomAccessFile é para trabalhar com arquivos de acesso aleatório. Basicamente vc teria que ter um arquivo bem estruturado, onde cada linha teria a mesma quantidade de bytes. Assim, vc consegue ir para o registro que quiser (dai que vem o “Random”) sem precisar passar os registros um por um, bastando apenas saber o número do registro. Dê uma pesquisada no google sobre arquivo de acesso randômico, ou arquivo de acesso aleatório. Vc vai achar muita coisa. Normalmente vc vai usar um banco de dados para armazenar seus registros, não precisando usar um arquivo desse tipo.

[]´s

A

davidbuzatto:
alexD:
Hum… acho que isso encerra o assunto (já que eu perdi as esperanças que alguem vá responder a 2ª duvida que eu coloquei la no 1º post).

Fica um obrigado a todo para mundo que veio aqui tirar minha duvida o/

E foi mal sobre isso de o topico virar novela, mas quando falaram desse lance de que o resultado do método poderia vir com um espaço a mais ou algo assim, me confundiu um poco.

De novo… vlw ae pessoal…

E já podem fechar o topico :smiley:

Então Alex, vc misturou um monte de coisa no seu primeiro post e eu acabei não lendo inteiro. Enfim, para facilitar a leitura de arquivos de texto vc pode usar a classe Scanner sim. Sem nenhum problema. A RandomAccessFile é para trabalhar com arquivos de acesso aleatório. Basicamente vc teria que ter um arquivo bem estruturado, onde cada linha teria a mesma quantidade de bytes. Assim, vc consegue ir para o registro que quiser (dai que vem o “Random”) sem precisar passar os registros um por um, bastando apenas saber o número do registro. Dê uma pesquisada no google sobre arquivo de acesso randômico, ou arquivo de acesso aleatório. Vc vai achar muita coisa. Normalmente vc vai usar um banco de dados para armazenar seus registros, não precisando usar um arquivo desse tipo.

[]´s

Ae… agora sim fechou tudo certinho :slight_smile:

vlw pela paciência ae :smiley:

Criado 22 de julho de 2010
Ultima resposta 23 de jul. de 2010
Respostas 20
Participantes 6