.jar que leia arquivo .txt que seja repassado a ele [RESOLVIDO]

Olá Pessoal,

Primeiro: já naveguei 3 horas pesquisando aqui e mais 2 pela internet e encontrei vários tópicos sobre leituras de arquivos dentro e fora de pacotes .jar, nenhum descreve meu problema. Também pesquisei em inglês em outros fóruns em outras horas, também nada.

Segundo: gostaria de saber de vocês se tem alguma ideia sobre isso:

Estou desenvolvendo uma biblioteca de programação para manipular ontologias, quero gerar um .jar para que outras pessoas possas utilizar em seus projetos inserindo-o no build path, ok.

O problema é que eu quero instanciar um objeto da minha classe principal e passar o caminho do txt nessa instanciação.

  • Não quero incluir o txt dentro do .jar.
  • Não quero deixar o txt junto do diretório do projeto.

Então para isso eu tenho um conjunto de classes onde é necessário que o programador inicie por:

Mediator med = new Mediator(ontologia,"C:/Users/Usuario/workspace/teste.txt",1); med.getKnowledgeRelation();

Ignorem ontologia, atentem para o caminho do txt.

Quando o .jar é usado dá uma série de erros quando chega nessa parte abaixo:

[code]File file = new File(this.archive);
InputStream reading;
try {
reading = new FileInputStream(file);

		InputStreamReader rLection = new InputStreamReader(reading);
		BufferedReader bLection = new BufferedReader(rLecture);
		
		String txtLector = bLecture.readLine();
		while(txtLector  != null){
			maxRows++;
			txtLector = bLecture.readLine();
		}
		bLecture.close();
		rLecture.close();
		reading.close();
	
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}[/code]

Onde no this.archive consta quela String com o caminho do txt. Dependendo dos projetos que andei testando, ocorre um dos dois grupos de exceções:

java.io.FileNotFoundException: (A sintaxe do nome do arquivo, do nome do diretório ou do rótulo do volume está incorreta) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:120) at ontocomAgent.communication.AgentMsgConversion.countFileRows(AgentMsgConversion.java:111) at ontocomAgent.communication.AgentMsgConversion.getMessageArray(AgentMsgConversion.java:203) at ontocomAgent.communication.Communication.getContent(Communication.java:61) at ontocomAgent.mediator.Mediator.getKnowledgeRelation(Mediator.java:202) at ontology.ontotest.execute(ontotest.java:29) at jason.asSemantics.TransitionSystem.applyExecInt(TransitionSystem.java:632) at jason.asSemantics.TransitionSystem.applySemanticRule(TransitionSystem.java:213) at jason.asSemantics.TransitionSystem.reasoningCycle(TransitionSystem.java:1186) at jason.infra.centralised.CentralisedAgArch.run(CentralisedAgArch.java:205) at java.lang.Thread.run(Thread.java:662)

java.lang.NullPointerException at java.io.Reader.<init>(Unknown Source) at java.io.InputStreamReader.<init>(Unknown Source) at ontocomAgent.communication.AgentMsgConversion.countFileRows(AgentMsgConversion.java:116) at ontocomAgent.communication.AgentMsgConversion.getMessageArray(AgentMsgConversion.java:207) at ontocomAgent.communication.Communication.getContent(Communication.java:61) at ontocomAgent.mediator.Mediator.getKnowledgeRelation(Mediator.java:202) at userAgent.setup(userAgent.java:30) at jade.core.Agent$ActiveLifeCycle.init(Agent.java:1522) at jade.core.Agent.run(Agent.java:1468) at java.lang.Thread.run(Unknown Source)

Meu projeto é este ontocomAgent. Sendo que no projeto deste .jar, no Eclipse, tudo está rodando normal, sem erros, é na utilização do .jar mesmo que tudo explode, hehe.
O que já verifiquei:

  • Já havia verificado permissões aqui no win7 e repassei todas (estou executando o ambiente como Admin também).
  • Tentei getResourceAsStream, getClass, outras funções para ler arquivos e nada, nada mesmo. As vezes, dependendo do código, até funciona, mas larga as exceções do mesmo jeito (bruxaria).
  • Já verifiquei se estou utilizando algo como null também em todas as classes, por causa do NullPointerException.
  • Obviamente já verifiquei se o caminho e o nome do arquivo poderiam estar errado, está tudo ok porque funciona de boa enquanto desenvolvo a lib.

Estou achando que existe uma limitação aí, o que acham?

Desculpa pessoal, deu erro de conexão de alguma coisa do Fórum e criou dois tópicos.

Nenhuma ideia? Não é possível que tenha uma limitação do Java aqui…

Boa noite Fabio.

Desconheço tal limitação…
Normalmente, isso é por falta de permissão - mas você comentou que checou…

O método file.exists() retorna o que?
Caso retornar ‘true’, verifique o file.canRead() e nos passe o resultado.

Atenciosamente,
Bruno

Olá Bruno, obrigado pela resposta,

Então, ambos métodos retornam true, não existem erros na leitura da info do teste.txt, mas após gerar o pacote .jar, ele lê o arquivo (faz tudo que está dentro do try) e ainda lança exceção (bruxaria hehe).

Essa bruxaria que eu digo e que parece não fazer sentido, testei em máquina com linux e windows, mesmo problema.

Minha aplicação usa dois métodos para ler arquivo. Esse daí que mostrei é pra fazer uma contagem de linhas somente, depois existe um segundo método, escrito quase da mesma forma, para pegar e manipular as informações do txt. Quando executados separadamente, as outras aplicações que usam o .jar não funciona. Quando executadas normal em conjunto como foi o planejado é que acontece a bruxaria, ele lê o txt, manipula os dados mas no último catch explode todas aquelas exceções que repassei.

Será que eu não tenho que usar uma outra forma de ler o arquivo? Com FileInputStream? Só que eu não queria ter que deixar o arquivo.txt dentro da pasta da aplicação (muito menos dentro do .jar), queria que fosse passado como parâmetro.

Mostre como está sendo feita a inicialização da variável archive.

Quem quiser ver a classe na integra (assim como todo o projeto) pode ver no meu github: https://github.com/fabiosperotto/ontoComAgent/blob/master/src/ontocomAgent/communication/AgentMsgConversion.java

Explicando o fluxo e inicialização da variável:
As aplicações que estou testando utilizam o seguinte objeto principal:

Mediator med = new Mediator(ontologia,"C:/Users/TxtFiles/teste.txt",1);

O caminho para o arquivo txt é repassado entre aspas como pode ser visto acima. Em seguida, quando um objeto for realizar uma manipulação de txt, chama um segundo objeto:

Communication commAgent = new Communication(); String[] queryConcepts = commAgent.getContent(this.message);

this.message possui uma mensagem simples ou o endereço do arquivo txt, neste caso está recebendo aquele diretório do teste.txt, aí então, um terceiro objeto é instanciado para fazer manipulação do arquivo:

AgentMsgConversion msg = new AgentMsgConversion(agentMessage);

Onde o atributo archive de AgentMsgConversion recebe o endereço do arquivo teste.txt.
[size=9]Não sei se era isso que me pediu…[/size]

É uma camada mediadora que faz manipulação de mensagens de arquivos txt, pega o conteudo, pesquisa na ontologia e depois devolve no arquivo, tudo funcional com o projeto na IDE, mas no .jar utilizado nas aplicações funciona só que também lança exceção. Pensei que era a forma como escrevia o caminho, já tentei com duas barras pra separar as pastas entre outros exemplos, .jar continua lançando exceção apesar de fazer o trabalho.

Pergunta. Você copiou esse código do seu programa mesmo? Se fez isso, está cheio de erros de compilação, e é por isso que você está batendo cabeça.

Como você deve estar sabendo (espero), o Eclipse deixa rodar programas com erros de compilação sem avisar. Ele só acaba gerando uma exception esquisita na hora que passa em uma linha em que houve erro de compilação. O nome da variável de leitura é rLection ou rLecture?

Uma dica: não é preciso criar um monte de variáveis de tipos diferentes (BufferedReader, InputStreamReader, FileInputStream etc.) para ler um simples arquivo. Se fizer o seguinte, você vai ler o danado do arquivo, e fechar tudo corretamente, porque o close da classe mais interna (BufferedReader) já chama o close das classes mais externas (InputStreamReader, FileInputStream). Basta olhar o fonte dessas classes. Veja como eu faria, no seu caso.

BufferedReader br = null;
try {
    br = new BufferedReader (new InputStreamReader (new FileInputStream (...)));
    for (String line = br.readLine(); line != null; line = br.readLine() ) {
        // tratar a linha lida
    }
} catch (IOException ex) {
    ...
} finally {
     if (br != null) try { br.close(); } catch (IOException ex2) { }
}

[quote=entanglement]Uma dica: não é preciso criar um monte de variáveis de tipos diferentes (BufferedReader, InputStreamReader, FileInputStream etc.) para ler um simples arquivo. Se fizer o seguinte, você vai ler o danado do arquivo, e fechar tudo corretamente, porque o close da classe mais interna (BufferedReader) já chama o close das classes mais externas (InputStreamReader, FileInputStream). Basta olhar o fonte dessas classes. Veja como eu faria, no seu caso.

BufferedReader br = null; try { br = new BufferedReader (new InputStreamReader (new FileInputStream (...))); for (String line = br.readLine(); line != null; line = br.readLine() ) { // tratar a linha lida } } catch (IOException ex) { ... } finally { if (br != null) try { br.close(); } catch (IOException ex2) { } } [/quote]

Na verdade meu eclipse bloqueia quando ha erros de programação e eu verifiquei por warnings também.

Um milhão de desculpas pelos equívocos, falta de controle da minha versão, veja:

Tem erros sim porque repassei uma versão que escrevi aqui direto em inglês, estou tentando não misturar inglês com português na programação, mas de qualquer forma: retirei a ultima versão do meu github, a classe completa está abaixo[size=18] [/size], com os dois métodos que em conjunto dão problema:

package ontocomAgent.communication;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;

/**
 * <p>
 * This class aims to be a tool to convert messages into KQML derived from text files (.txt) in two-dimensional arrays.
 * </p>
 */
public class AgentMsgConversion {

	private String archive;

	/**
	 * <p>Class constructor (need inform the path to file)</p>
	 * @param archiveAddres
	 */
	public AgentMsgConversion(String archiveAddres) {
		this.archive = archiveAddres;
	}

	/**
	 * <p>Returns the path of the file.</p>
	 * @return String archive
	 */
	public String getArchive() {
		return archive;
	}

	/**
	 * <p>Set the path of the file.</p>
	 * @param archive
	 */
	public void setArchive(String archive) {
		this.archive = archive;
	}

	/**
	 * <p>A counter to determine how much lines the txt file have.</p>
	 * @return maxRows
	 */
	public int countFileRows(){
		int maxRows = 0;

		try {

			File file = new File(this.archive);

			// get the size of file
			long sizeFile = file.length();
			FileInputStream inputStream = new FileInputStream(file);
			DataInputStream inputData = new DataInputStream(inputStream);

			LineNumberReader lineRead = new LineNumberReader(new InputStreamReader(inputData));
			lineRead.skip(sizeFile);
			// count the lines from file, start in zero
			maxRows = lineRead.getLineNumber();
			//System.out.println("lines in file: " + maxRows);

			inputStream.close();
			inputData.close();
			lineRead.close();

			}catch (IOException error) {
				System.out.println("Error countFileRows: "+error.getMessage());
				System.exit(0);
			}

		return maxRows;
	}

	/**
	 * <p>Provides a way to transform a txt KMQL Message in a Array. The Array is bidimensional, where each line of a message is a pair in array.</p>
	 * Example:
	 * If a message has
	 * <pre>
	 * (request
	 * 	:sender (agent-identifier :name X)
	 * 	:receiver (agent-identifier :name Y)
	 * 	:content (Z)
	 * 	:protocol fipa-request
	 * )</pre>
	 * The function return the array:
	 * <table border=1>
	 * <tr>
	 * 	<td>0</td>
	 *  <td>Performative</td>
	 *  <td>request</td>
	 * </tr>
	 * 
	 * <tr>
	 * 	<td>1</td>
	 *  <td>:sender</td>
	 *  <td>agent-identifier :name X</td>
	 * </tr>
	 * 
	 * <tr>
	 * 	<td>2</td>
	 *  <td>:receiver</td>
	 *  <td>agent-identifier :name Y</td>
	 * </tr>
	 * 
	 * <tr>
	 * 	<td>3</td>
	 *  <td>:content</td>
	 *  <td>(Z)</td>
	 * </tr>
	 * 
	 * <tr>
	 * 	<td>4</td>
	 *  <td>:protocol</td>
	 *  <td>fipa-request</td>
	 * </tr>
	 * </table>
	 * @return String[][] mounted with 2 columns
	 */	
	public String[][] getMessageArray(){

		int maxRows = countFileRows();
		int maxCol = 2;
        
        String[][] mounted = new String[maxRows][maxCol];
        int row = 0;

		try{

			File file = new File(this.archive);

			FileInputStream inputs = new FileInputStream(file);  
                        InputStreamReader reader = new InputStreamReader(inputs);  
                        BufferedReader buffer = new BufferedReader(reader);
                                                
                        mounted[row][maxCol-2] = "Performative";
            
                        String valueTxt = buffer.readLine();
            
                        mounted[row][maxCol-1] = valueTxt.replace("(", "");
                        //System.out.println(mounted[0][0]);
                        //System.out.println(mounted[0][1]);            
                  
                        String[] unmounted;
                       while((valueTxt = buffer.readLine()) != null){
            	          //System.out.println("ITEM: "+valueTxt);
            	          if(valueTxt.contentEquals(")")){
            		       break;
            	         }
            	        row++;
            	
            	        // checking different lines breaks 
            	        unmounted = valueTxt.split("[()]");            	            	
            	        if(unmounted.length == 2){
            		     mounted[row][maxCol-2] = unmounted[0].trim();
            		     mounted[row][maxCol-1] = unmounted[1].trim();
        
                   }else{
            		unmounted = valueTxt.split(" ");
            		mounted[row][maxCol-2] = unmounted[0].trim();
            		mounted[row][maxCol-1] = unmounted[1].trim();

                }
            	
            }                 
                        
            inputs.close();
            reader.close();
            buffer.close();
                        
		}catch(IOException error){
			System.out.println("Error getMessageArray: "+error.getMessage());
			System.exit(0);

		}
		return mounted;
	}	
}

Também testei, mas não se encontra acima, o fechamento do arquivo conforme você me repassou e eu não sabia mesmo. Mas nada mudou, tudo ainda continua fluindo pelo eclipse mas o .jar lança exceções.

Pessoal, acho que resolvi por hora e a maior parte da culpa foi minha por falta de atenção nas classes que usam esta classe manipuladora de txt além de eu estar fechando o arquivo erroneamente.

Obrigado a todos que me ajudaram nesse tópico.

[size=18]Resolução:[/size]
[list]Peguei as dicas do usuário entanglement e refiz o código da classe acima, agora sim, usando menos variáveis e fechando apenas o que precisa.[/list]
[list]Depois verifiquei o absolutepath, inclusive utilizei um JFileChooser do Swing para confirmar se eu estava passando o arquivo corretamente e o divisor de diretórios é a contra barra, ficando assim o endereço do arquivo c:\diretorio\mensagem.txt[/list]

[list]Por exemplo, um dos métodos da classe do post anterior ficou como:[/list]
[code]public int countFileRows(){
int maxRows = 0;

	try {  
		FileReader file = new FileReader(this.archive);  
        BufferedReader buffer = new BufferedReader(file);
        
		while((buffer.readLine()) != null){
			 maxRows++;
	    }
		 
		file.close(); 
	} catch (IOException err) {  
		System.out.println("Error countFileRows: "+err.getMessage());
	   
	} 				
	return maxRows;		
}[/code]

[list]Além de corrigir essa parte verifiquei que minha biblioteca de programação fazia dupla chamada do método getMessageArray(). Uma seguida depois da outra, olhando bem as classes em volta, notei que meu código estava certo mas sendo reusado erroneamente, só alterei uma linha que chamava uma vez essa classe que manipula txt. Em seguida, tudo floresceu lindamente nos outros sistemas, haha. Os sistemas usuários não podem ter dupla chamada com processamento de arquivos no mesmo contexto, eu entendi assim, pelo menos. :? [/list]

Desculpem o incômodo, agradeço fortemente e vou passar os ensinamentos para frente! Minha biblioteca continuará sendo desenvolvida e será software livre forever. :stuck_out_tongue:

Estou testando o projeto com esses dois sistemas e parece tudo ok por enquanto:
http://jason.sourceforge.net/wp/
http://jade.tilab.com/