2017-09-26 1 views
0

Je ne connais pas très bien Java, et j'essaie d'utiliser Java dans un projet Processing.org 3. J'ai réussi à reconstruire le problème dans un petit exemple de traitement appelé testprocjavapath - et je poste un script bash (appelé testProcJavaLoadpath.sh) qui reconstruit les exemples de fichiers de projet à la fin de ce post, et exécute le projet une fois. Les fichiers de projet testprocjavapath ressemblent à ceci:Processing.org 3 et le chargement des fichiers de propriétés Java?

~/sketchbook/testprocjavapath 
├── testprocjavapath.pde 
├── myprops.properties 
└── MyJavaClass.java 

Lors de l'exécution du script, je reçois ceci:

$ bash testProcJavaLoadpath.sh 
... 
There was an exception myprops.properties: java.lang.NullPointerException : null 
The properties file content is 'null'; 
Finished. 

Debugging dans le traitement 3 GUI IDE, cette erreur se produit exactement sur la ligne properties.load(in);:

Processing-testprocjavapath.png

... parce que la ligne InputStream in = MyJavaClass.class.getResourceAsStream(inFileName); a échoué, et par conséquent, in est un pointeur null.

Ce que je comprends - ce que je ne comprends pas: comment puis-je charger un, par exemple, un fichier texte .properties, dans le même répertoire que le fichier croquis traitement .pde et le fichier .java (qui est, ce particulier dossier de croquis)?

Pour autant que je déduis Java getResourceAsStream() est effectivement utilisé pour charger à partir d'une application Java emballé sous forme de fichier .jar - donc peut-il travailler pour la lecture des fichiers à partir du disque dur, qui ne sont pas encore emballés comme .jar fichiers?

Si non - j'ai aussi essayé de le faire:

InputStream in = new FileInputStream(new File(PROPERTIES_FILENAME)); 

... mais cela ne fonctionne pas non plus (in est à nouveau null).

Alors, quelle commande puis-je utiliser dans le fichier .java pour charger le fichier myprops.properties? Et si je devais finir par emballer toute l'application de traitement sous la forme d'un fichier .jar (je ne suis pas sûr que Processing puisse le faire, je ne l'ai pas encore cherché), devrais-je changer cette commande?


Voici le testProcJavaLoadpath.sh fichier (assurez-vous de changer PROCBINPATH à votre chemin d'installation de traitement):

PROCSKETCHDIR="~/sketchbook" 
PROCSKETCHDIR="${PROCSKETCHDIR/#\~/$HOME}" # expand home dir ~ 
echo "$PROCSKETCHDIR" 
PROCBINPATH="/PATH/TO/processing-3.3.6" # path/location of Processing executable `processing-java` 

MYSKETCH="testprocjavapath" 
MYSKETCHDIR="$PROCSKETCHDIR/$MYSKETCH" 
# reconstruct folder: 
rm -rfv "$MYSKETCHDIR" 
mkdir -v "$MYSKETCHDIR" 

echo "generating $MYSKETCHDIR/$MYSKETCH.pde" 
cat > "$MYSKETCHDIR/$MYSKETCH.pde" <<'EOF' 

void setup() { 
    size(640, 360); // Size should be the first statement 
    MyJavaClass myjc = new MyJavaClass(); 
    String thefilecontents = myjc.GetPropsFileContent(); 
    System.out.format("The properties file content is '%s';%n", thefilecontents); 
} 

EOF 

echo "generating $MYSKETCHDIR/myprops.properties" 
cat > "$MYSKETCHDIR/myprops.properties" <<'EOF' 
teststr=HelloWorld 
EOF 

echo "generating $MYSKETCHDIR/MyJavaClass.java" 
cat > "$MYSKETCHDIR/MyJavaClass.java" <<'EOF' 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Properties; 
import java.io.FileInputStream; 
import java.io.File; 
import java.io.ByteArrayOutputStream; 

public class MyJavaClass { 

    private static final String PROPERTIES_FILENAME = "myprops.properties"; 

    /** 
    * add a constructor 
    */ 
    public static void MyJavaClass() { 
    } 

    public static String GetPropsFileContent() { 
    String myret = null; 
    myret = readgetFileContent(PROPERTIES_FILENAME); 
    return myret; 
    } 

    public static String readgetFileContent(String inFileName) { 
    String result = null; 
    Properties properties = new Properties(); 
    try { 
     InputStream in = MyJavaClass.class.getResourceAsStream(inFileName); 
     properties.load(in); 

     ByteArrayOutputStream resultbaos = new ByteArrayOutputStream(); 
     byte[] buffer = new byte[1024]; 
     int length; 
     while ((length = in.read(buffer)) != -1) { 
     resultbaos.write(buffer, 0, length); 
     } 
     result = resultbaos.toString(); 
    } catch (IOException e) { 
     System.err.println("There was an error reading " + inFileName + ": " + e.getCause() 
      + " : " + e.getMessage()); 
    } catch (Exception e) { 
     System.err.println("There was an exception " + inFileName + ": " + e 
      + " : " + e.getMessage()); 
    } 
    return result; 
    } 
} 
EOF 

# run once: 
"$PROCBINPATH"/processing-java --sketch="$MYSKETCHDIR" --run 
+0

Je suis assez confus au sujet de ce que vous essayez de faire. Pourriez-vous peut-être essayer d'afficher un plus petit [mcve]? Quelque chose d'aussi simple que 'println (nouveau fichier (" test.txt "). GetAbsolutePath())' irait assez loin pour aider à comprendre ce que vous attendez de ce qui se passe réellement. Aussi, comment compilez-vous et exécutez-vous cela? –

Répondre

0

Ok, j'ai réussi à aller quelque part - mais je voudrais encore une plus réponse qualifiée.

Tout d'abord, il se trouve, le traitement en tant que tel se attendre à des fichiers à lire (comme myprops.properties dans l'exemple OP), à stocker dans un sous-dossier data du dossier croquis:

https://processing.org/tutorials/data/

De même que pour les fichiers image, ces fichiers texte doivent être placés dans le répertoire "data" de l'esquisse afin qu'ils soient reconnus par l'esquisse de traitement.

Jusqu'à présent, si bien - et en effet, à l'intérieur du traitement .pde croquis, nous pouvons utiliser (par exemple) loadStrings("myprops.properties"); et le fichier à data/myprops.properties sera lu. Cependant, je n'ai pas besoin de lire le fichier - je dois le lire dans la classe .java. Maintenant, lorsque vous exécutez le correctif Traitement (depuis IDE ou depuis la ligne de commande), Processing copie les fichiers sources du dossier sketch, dans un dossier temporaire du dossier /tmp (au moins sur Linux); voici comment cette structure de fichier ressemble:

/tmp/testprocjavapath9179591342074530534temp/ 
├── MyJavaClass.class 
├── source 
│   ├── MyJavaClass.java 
│   └── testprocjavapath.java 
└── testprocjavapath.class 

Notez que nous avons .java fichiers source et .class « compilé » fichiers, mais il n'y a pas data sous-dossier ou fichier myprops.properties partout!

Maintenant, notez également que ce qui était auparavant testprocjavapath.pde dans le dossier d'esquisse source, devient testprocjavapath.java (et .class correspondant) dans le dossier temporaire; remarquer que testprocjavapath.java définit:

public class testprocjavapath extends PApplet { 

Maintenant, le loadStrings est en fait une méthode de la classe PApplet; Donc, si nous lisons un peu:

https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java

dataPath(String where): .... Le chemin de données sont traitées différemment sur chaque plate-forme, et ne doit pas être considéré comme un lieu d'écrire des fichiers. Il ne doit pas non plus être supposé que cet emplacement peut être lu ou listé. ... Les bibliothèques doivent utiliser createInput() pour obtenir un InputStream ou createOutput() pour obtenir un OutputStream. sketchPath() peut être utilisé pour obtenir un emplacement relatif à l'esquisse. Encore une fois, ne pas utiliser pour obtenir les emplacements relatifs des fichiers. ...

... nous pouvons voir une méthode dataPath, mais son utilisation n'est pas recommandée. D'autre part, il existe une méthode sketchPath - cependant, cette méthode ne retourner le bon chemin (par exemple une esquisse dans ~/sketchbook dans cet exemple) si appelé à partir du haut niveau fichier .pde! Si vous essayez d'avoir la classe dans le fichier .java défini comme extends PApplet, puis appelez sketchPath à partir de là - il retournera simplement le répertoire de travail en cours!

Ainsi, la solution est maintenant:

  • Demandez la .java classe accepte un argument d'entrée dans le constructeur, qui sera utilisé pour enregistrer le chemin croquis approprié:
     public MyJavaClass(String inSketchPath) {
  • Puis, ont le sketchPath() passé à l'instance de classe .java lors de l'instanciation dans le fichier .pde:
     MyJavaClass myjc = new MyJavaClass(sketchPath());
  • Enfin, utilisez le chemin croquis passé à l'intérieur de la classe .java, pour calculer le chemin absolu du .properties fichier, puis le charger avec new FileInputStream(new File(theFilePath)); (pas avec getResourceAsStream!)

Ci-dessous un changement testProcJavaLoadpath.sh est collé, qui a ces modifications, et en principe, fonctionne - c'est la borne de sortie:

$ bash testProcJavaLoadpath.sh 
... 
Sketch first lines: 'teststr=HelloWorld'; 
Sketch dataFile: '~/sketchbook/testprocjavapath/data/myprops.properties'; 
Sketch sketchPath: '~/sketchbook/testprocjavapath'; 
:: mySketchPath: '~/sketchbook/testprocjavapath' 
:: The URL is 'file:/tmp/testprocjavapath4709659129218148940temp/'; 
:: name: MyJavaClass.class 
:: resourcePath: file:/tmp/testprocjavapath4709659129218148940temp/MyJavaClass.class 
:: theFilePath: '~/sketchbook/testprocjavapath/data/myprops.properties' 
:: properties: key 'teststr' => value 'HelloWorld' 
The properties file content is 'teststr=HelloWorld 
'; 

... cependant, j'imagine que si je veux emballer ce code dans un .jar ou une application/fichier exécutable, cette approche échouerait probablement - c'est pourquoi je voudrais toujours une réponse plus qualifiée.

Le changé testProcJavaLoadpath.sh est ceci:

PROCSKETCHDIR="~/sketchbook" 
PROCSKETCHDIR="${PROCSKETCHDIR/#\~/$HOME}" # expand home dir ~ 
echo "$PROCSKETCHDIR" 
PROCBINPATH="/PATH/TO/processing-3.3.6" # path/location of Processing executable `processing-java` 

MYSKETCH="testprocjavapath" 
MYSKETCHDIR="$PROCSKETCHDIR/$MYSKETCH" 
# reconstruct folder: 
rm -rfv "$MYSKETCHDIR" 
mkdir -v "$MYSKETCHDIR" 

# https://processing.org/tutorials/data/ 
# "And just as with image files, these text files should be placed in the sketch’s “data” directory in order for them to be recognized by the Processing sketch." 
# processing.core.PApplet.loadStrings - https://processing.github.io/processing-javadocs/core/ 
# https://github.com/processing/processing/blob/master/core/src/processing/core/PApplet.java 
# "dataPath(String where): The data path is handled differently on each platform, and should not be considered a location to write files. It should also not be assumed that this location can be read from or listed. ... Libraries should use createInput() to get an InputStream or createOutput() to get an OutputStream. sketchPath() can be used to get a location relative to the sketch. Again, <b>do not</b> use this to get relative locations of files." 

echo "generating $MYSKETCHDIR/$MYSKETCH.pde" 
cat > "$MYSKETCHDIR/$MYSKETCH.pde" <<'EOF' 

void setup() { 
    size(640, 360); // Size should be the first statement 
    String[] lines = loadStrings("myprops.properties"); // reads from data/myprops.properties 
    System.out.format("Sketch first lines: '%s';%n", lines[0]); 
    System.out.format("Sketch dataFile: '%s';%n", dataFile("myprops.properties")); // ~/sketchbook/testprocjavapath/data/myprops.properties 
    System.out.format("Sketch sketchPath: '%s';%n", sketchPath()); // ~/sketchbook/testprocjavapath 
    MyJavaClass myjc = new MyJavaClass(sketchPath()); 
    String thefilecontents = myjc.GetPropsFileContent(); 
    System.out.format("The properties file content is '%s';%n", thefilecontents); 
} 

EOF 

mkdir -v "$MYSKETCHDIR/data" 
echo "generating $MYSKETCHDIR/data/myprops.properties" 
cat > "$MYSKETCHDIR/data/myprops.properties" <<'EOF' 
teststr=HelloWorld 
EOF 

echo "generating $MYSKETCHDIR/MyJavaClass.java" 
cat > "$MYSKETCHDIR/MyJavaClass.java" <<'EOF' 
import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStream; // "InputStream is by definition not seekable." 
import java.io.InputStreamReader; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Properties; 
import java.io.FileInputStream; // is seekable 
import java.io.File; 
import java.io.ByteArrayOutputStream; 
import java.net.URL; 

//import processing.core.*; 
import java.nio.file.Path; 
import java.nio.file.Paths; 

public class MyJavaClass { 

    private static final String PROPERTIES_FILENAME = "myprops.properties"; 
    public String mySketchPath; 

    /** 
    * add a constructor 
    */ 
    public MyJavaClass(String inSketchPath) { 
    mySketchPath = inSketchPath; 
    } 

    public String GetPropsFileContent() { 
    //System.out.format(":: sketchPath: '%s'%n", sketchPath()); // if `MyJavaClass extends PApplet`, then sketchPath() just prints current working directory! 
    System.out.format(":: mySketchPath: '%s'%n", mySketchPath); 
    getLocations(); 
    String myret = null; 
    myret = readgetFileContent(PROPERTIES_FILENAME); 
    return myret; 
    } 

    public String readgetFileContent(String inFileName) { 
    String result = null; 
    Properties properties = new Properties(); 
    try { 
     //String theFilePath = inFileName; // verbatim relative path fails 
     Path inFileNameSketchPath = Paths.get(mySketchPath, "data", inFileName); // OS path join 
     String theFilePath = inFileNameSketchPath.toString(); 
     System.out.format(":: theFilePath: '%s'%n", theFilePath); 

     //InputStream in = MyJavaClass.class.getResourceAsStream(theFilePath); // no can do, is 'null', also w/ abs path 
     //InputStream in = new FileInputStream(new File(theFilePath)); // OK, but not seekable 
     FileInputStream in = new FileInputStream(new File(theFilePath)); 
     properties.load(in); 

     // double-check loaded properties: 
     for(String key : properties.stringPropertyNames()) { 
     String value = properties.getProperty(key); 
     System.out.format(":: properties: key '%s' => value '%s'%n", key, value); 
     } 

     ByteArrayOutputStream resultbaos = new ByteArrayOutputStream(); 
     byte[] buffer = new byte[1024]; 
     int length; 
     in.getChannel().position(0); // do reset - seek 0 (start), to reset stream again for reading 
     while ((length = in.read(buffer)) != -1) { 
     resultbaos.write(buffer, 0, length); 
     } 
     result = resultbaos.toString(); 
    } catch (IOException e) { 
     System.err.println("There was an error reading " + inFileName + ": " + e.getCause() 
      + " : " + e.getMessage()); 
    } catch (Exception e) { 
     System.err.println("There was an exception " + inFileName + ": " + e 
      + " : " + e.getMessage()); 
    } 
    return result; 
    } 

    public void getLocations() { 
    URL classURL = getClass().getProtectionDomain().getCodeSource().getLocation(); 
    System.out.format(":: The URL is '%s';%n", classURL); // file:/tmp/testprocjavapath3056820301028631180temp/ 

    String s = getClass().getName(); 
    int i = s.lastIndexOf("."); 
    if(i > -1) s = s.substring(i + 1); 
    s = s + ".class"; 
    System.out.println(":: name: " + s); 
    Object resourcePath = this.getClass().getResource(s); 
    System.out.println(":: resourcePath: " + resourcePath); // file:/tmp/testprocjavapath9185318125154993853temp/MyJavaClass.class 
    } 
} 
EOF 

# run once: 
"$PROCBINPATH"/processing-java --sketch="$MYSKETCHDIR" --run