2017-09-26 94 views
0

我不是那麼熟悉Java,我正在嘗試在Processing.org 3項目中使用一些Java。我已經設法在一個名爲testprocjavapath的小型處理示例項目中重新構建問題 - 並且我發佈了一個bash腳本(稱爲testProcJavaLoadpath.sh),該腳本重構了本文末尾的示例項目文件,並運行了一次項目。該testprocjavapath項目文件看起來像這樣:Processing.org 3並加載Java屬性文件?

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

運行腳本時,我得到這個:

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

調試在處理3個IDE界面上會出現此錯誤完全行properties.load(in);

Processing-testprocjavapath.png

...因爲線路InputStream in = MyJavaClass.class.getResourceAsStream(inFileName);失敗,因此in是一個空指針。

說得多我明白 - 我不明白的是:我怎麼加載,比方說,.properties文本文件,在同一目錄中.pde處理素描文件和.java文件(即,這個特殊的素描文件夾)?

據我收集了Java getResourceAsStream()實際上被用於從包裝爲.jar文件中的Java應用程序中加載 - 因此可以將它用於讀取硬盤中的文件,還未被打包爲.jar文件?

如果沒有 - 我也試圖做的事:

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

...但是這並沒有工作,要麼(in再次null)。

那麼,我可以在.java文件中使用什麼命令來加載myprops.properties文件?如果我最終應該將整個Processing應用程序打包爲.jar文件(不確定Processing是否可以這樣做,還沒有查看它),我是否必須更改該命令?


這裏是testProcJavaLoadpath.sh文件(請確保您更改PROCBINPATH您處理安裝路徑):

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

我很困惑你想要做什麼。你可能會嘗試發佈一個更小的[mcve]?就像'println(new File(「test.txt」)。getAbsolutePath())'一樣簡單,可以幫助您理解您期望發生的事情與實際發生的事情。另外,你如何編譯和運行它? –

回答

0

好吧,我設法得到的地方 - 但我還是想更合格的答案。

首先,事實證明,加工爲這樣的期望要被讀取的文件(如在OP示例myprops.properties),將被存儲在一個data子目錄草圖文件夾:

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

就像圖像文件一樣,這些文本文件應放置在草圖的「數據」目錄中,以便它們被Processing草圖識別。

到目前爲止好 - 事實上,在處理.pde草圖裏面,我們可以使用(比方說)loadStrings("myprops.properties");,在data/myprops.properties文件將被讀取。但是,我不需要在那裏讀取文件 - 我需要在支持.java的課程中閱讀它。

現在,當您運行Processing修補程序(無論是從IDE還是從命令行),會發生什麼情況是Processing會將源文件從sketch文件夾複製到/tmp文件夾中的臨時文件夾中(至少在Linux的);以下是文件結構的樣子:

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

注意到我們.java源文件,並.class「編譯」的文件,但沒有data子文件夾或文件myprops.properties任何地方!

現在,請注意,源素描文件夾中曾經是testprocjavapath.pde的東西在臨時文件夾中變成testprocjavapath.java(和相應的.class);注意到testprocjavapath.java定義:

public class testprocjavapath extends PApplet { 

現在,loadStrings實際上是PApplet類的方法;所以,如果我們通讀了一下:

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

dataPath(String where):....數據路徑不同的方式處理每一個平臺上,而不應被視爲一個位置寫入文件。也不應該假定這個位置可以被讀取或列出。 ...庫應該使用createInput()來獲取InputStream或createOutput()來獲取OutputStream。 sketchPath()可用於獲取相對於草圖的位置。再次,不要使用此來獲取文件的相對位置。 ...

...我們可以看到一種方法dataPath,但不推薦使用它。另一方面,有一個方法sketchPath - 但是,這種方法將只有返回正確的路徑(即在此示例~/sketchbook草圖)如果從頂級.pde文件調用!如果您嘗試將.java文件中的類定義爲extends PApplet,然後從那裏調用sketchPath - 它將僅返回當前工作目錄!

所以現在的解決方案是:

  • .java類接受的構造函數的輸入參數,它會被用來記錄正確的草圖路徑:
     public MyJavaClass(String inSketchPath) {
  • 然後,已在sketchPath()通過在.pde文件中的實例化過程中到.java類實例:
     MyJavaClass myjc = new MyJavaClass(sketchPath());
  • 最後,使用.java類中傳遞的草圖路徑來計算的絕對路徑文件,然後加載它new FileInputStream(new File(theFilePath));不是getResourceAsStream!)

下面一個改變testProcJavaLoadpath.sh粘貼,具有這些修改,原則,工作 - 這是終端輸出:

$ 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 
'; 

...但是,我想,如果我想將此代碼打包到.jar或可執行應用程序/文件中,這種方法可能會失敗 - 這就是爲什麼我仍然想要更合適的答案。

的改變testProcJavaLoadpath.sh是這樣的:

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