-2

This is the first question I ask on stackoverflow, so if you notice something unpleasant/bad/inappropriate in my question, please be kind and point it out to me.

I have tried doing my school homework in Java, because I was tired of C++ and I had already done something in Python. However, I've had problems with reading from a binary file (which should contain one double and two float numbers, in order).

Specifically: .getResource(filename) finds the file, but when I open a FileInputStream(path) (inside public static Integer Leggere(Dati [] dato, String nomefile)), it throws FileNotFoundException.

This is my code:

import java.util.*;
import java.io.*;

public class Main{
    public static void main(String[] args) {
        Dati [] data  = new Dati[23500];
        int contatore = 0;
        for(; contatore < 23500; contatore++){
            data[contatore] = new Dati(0, 0, 0);
        }
        contatore = 0;

        String path = Dati.class.getClassLoader().getResource("valori.bin").getPath().toString();
        contatore = Leggere(data, path);
        Acquisire(data, contatore);
        Scrivere(data, "risultati.txt", contatore);
    }

    public static Integer Leggere(Dati [] dato, String nomefile){
        int j = 0;
        try{
            DataInputStream in = new DataInputStream(new FileInputStream(nomefile));
            while(in.available() > 0){
                dato[j].dato1 = in.readDouble();
                dato[j].dato2 = in.readFloat();
                dato[j].dato3 = in.readFloat();
                j++;
            }
            in.close();
        }
        catch(IOException e){
            System.out.println("Problemi nell'apertura del file");
            System.out.println(nomefile);
            System.exit(0);
        }

        return j;
    }

    public static void Scrivere(Dati [] dato, String nomefile, int count){
        PrintWriter output;
        try {
            output = new PrintWriter(nomefile);

            Integer j = 0;
            while(j < count){
                output.println(dato[j]);
                j++;
            }

            output.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }


    }

    public static void Acquisire(Dati [] dato, int count){
        Scanner cinput = new Scanner(System.in);
        double c = 0.0;
        int j = 0;

        System.out.println("Inserisci un fattore di conversione: ");
        while(c == 0.0){
            c = cinput.nextDouble();
        }

        while(j < count){
            dato[j].dato1 *= c;
            dato[j].dato2 *= c;
            dato[j].dato3 *= c;
        }

        cinput.close();
    }
}

The program ends with two messages, which handle the exception. The second one is the path of the file as found by the getResource() method:

Problemi nell'apertura del file
/C:/Users/Sebastian/Desktop/Archivio/Scuola/5C%20a.s.%202016-2017/Compiti%20Estate%202016/Informatica/03%20-%20Conversione/bin/valori.bin

I know that it's a FileNotFoundException because it says so in debug mode.

How would you have done this piece of code? Do you know what the problem is? Could you post an example to fix the problem or an example of an alternative method to cope with it?

SOLUTION TO THE PROBLEM

I'm writing this so that people with a similar problem may find their solution.

"Malfunctioning" code

String path = Dati.class.getClassLoader().getResource("valori.bin").getPath().toString();
DataInputStream in = new DataInputStream(new FileInputStream(path));

What happened was that .getResource("valori.bin") managed to find the file (and it's path with .getPath()), but when I tried to open a FileInputStream(path), I got a FileNotFoundException.

Working code

InputStream stream = Dati.class.getClassLoader().getResourceAsStream("valori.bin");
DataInputStream in = new DataInputStream(stream);

This way does it. By doing so, I don't need to worry about path name because .getResourceAsStream() returns the usable Stream as is. I don't know exactly why the former code didn't work, but heuristics tells me to not worry much, and so be it!

  • Off the top of my head, one of the APIs might be using a relative path, while the other requires an absolute path, which path you may be getting wrong. – Tim Biegeleisen Sep 11 '16 at 15:07
  • @Tim Biegeleisen Oh, I see. Well, FileInputStream() is getting `/C:/Users/Sebastian/Desktop/Archivio/Scuola/5C%20a.s.%202016-2017/Compiti%20Estate%202016/Informatica/03%20-%20Conversione/bin/valori.bin` as a parameter. This is an absolute path, isn't it? – Sebastian Irimescu Sep 11 '16 at 15:28
  • Is the file name really that, with all the URL-encoding? – Robert Sep 11 '16 at 15:37
  • @Robert It is what `String path = Dati.class.getClassLoader().getResource("valori.bin").getPath().toString();` gives me when i visualize it with System.out – Sebastian Irimescu Sep 11 '16 at 15:41
  • Yes, but that is URL-encoded, which may make sense in some cases. However, a file system does not deal with URL-encodings and treats the name as-is. Revert the URL-encoding using https://docs.oracle.com/javase/7/docs/api/java/net/URLDecoder.html#decode(java.lang.String,%20java.lang.String) – Robert Sep 11 '16 at 15:44
  • @Robert Decoding doesn't actually fix my problem. File still isn't found by FileInputStream. What happens is that the path no longer has the "%20", instead they've been replaced by blank spaces. – Sebastian Irimescu Sep 11 '16 at 16:00
  • @Jarrod Roberson Regarding the question being "marked as duplicate", it is true that this question has already an answer in the link you indicated. However, in my opinion, the answer in that link might not be "simple" enough for students, as there are too many references and little linearity. I, for instance, couldn't understand a thing when I first saw that question. In this question, on the other hand, I have tried to summarize the solution to my problem so that it may be easily understood by new programmers like me, so, in spite of being a duplicate, this question might still be useful. – Sebastian Irimescu Sep 11 '16 at 23:51

1 Answers1

1

You might want to take a look at the getResourceAsStream method in the class loader. It gives you an input stream that you can plug directly and not have to deal with full paths and those kinds of problems.

Joe C
  • 15,324
  • 8
  • 38
  • 50
  • Okay, thank you. I've tried doing this in main: `InputStream stream = Dati.class.getClassLoader().getResourceAsStream("valori.bin");` and changed everything in the function Leggere() to make it work. It appears now that it manages to open it, but I'm having an EOF exception after reading a few bytes from the file, but I guess that that's a whole different problem to handle. Time to fix the Python program that actually writes in binary on that file. Might be because of the 64 bit Python float that I'm having Java 32 bit float errors. – Sebastian Irimescu Sep 11 '16 at 16:15