2010-03-07 43 views
2

在過去的幾個月裏,我一直在爲一個大學項目開發​​一個Java遊戲。這是即將到項目結束,我想編譯成一個易於分發的單個文件的項目。遊戲目前從IDE內部運行,並依賴於在特定位置設置的工作目錄(即具有聲音/紋理等的內容目錄)。將所有這些組合在一起以實現可移植性的最佳方式是什麼?我希望有一些方法可以將內容編譯到jar文件中...發佈一個帶有內容的Java程序

注意:我使用NetBeans,所以它很容易在NetBeans的任何解決方案中得到加分;)

附錄::

以供將來參考,我發現通過目錄訪問事物的一種方式,ythis可能不是最好的的方式,但它的工作原理:

File directory = new File(ClassLoader.getSystemResource("fullprototypeone/Content/Levels/").toURI()); 

而且現在就可以使用該文件對象爲正常

+1

如何使用ant build腳本將所有類和資源文件添加到自我可執行Jar文件中? – Pool 2010-03-07 00:10:33

+0

聽起來不錯,但我不知道螞蟻不幸的是:(爲什麼有人downvote這個? – Martin 2010-03-07 01:49:28

+0

如承諾我已經發布了一些代碼作爲一個新的答案。它可能會幫助你開始尋找在JAR內的每個目錄中的文件 – TofuBeer 2010-03-07 17:36:52

回答

7

您可以將資源嵌入到jar文件中 - 畢竟這只是一個zip文件。標準的做法是將資源文件放在源代碼層次的某個目錄中。然後通過Object.getClass()。getResourceAsStream()引用它們。所以你需要改變你在代碼中檢索它們的方式。

您可以在這裏閱讀更多:Object.getClass().getResourceAsStream()。當然,您可以使用包中的某些類而不是對象。

當你把這些資源文件放到你的src層次結構中時我相信Netbeans應該用你的項目的標準構建來爲你打包它們。

+0

這對所有直接使用單個文件的東西都有效,是否有辦法將包視爲目錄並掃描其中的所有文件?這是當前的金磚四國k牆我打了。 – Martin 2010-03-07 02:23:37

+0

@Martin是的,但這並不是微不足道的。我會看看如果我能找到一些代碼,我可以做到這一點(很確定我可以......但將是明天)。 – TofuBeer 2010-03-07 05:02:13

+0

你可以使用JarFile,但TofuBeer說它並不那麼簡單。我會建議一些其他的東西:在構建項目時,您可以預先計算資源列表並將其嵌入到文件中,例如filelist.properties。你讀這個文件並知道你擁有的所有資源。 – pajton 2010-03-07 07:58:58

1

那麼一種方法是通過Class.getResourceAsStream(或Class.getResource)訪問資源。然後確保這些文件在JAR文件中。

關閉我的頭頂(而不嘗試它),您應該能夠將源文件放入源文件中,以便NetBeans將它們放入JAR文件中。然後將File stuff更改爲getResource調用。

我會建議製作一個簡單的程序,播放聲音並在嘗試轉換整個項目之前嘗試一下。

如果你嘗試,它不起作用,讓我知道,我會看看如果我可以多挖一點(張貼簡單的項目的代碼將是很好的,如果說到這一點)。

0

是的!把你編譯的.class文件和你的資源與文件夾放在一個jar文件中..你將不得不建立一個清單文件以及..你可以找到關於在谷歌上創建一個.jar文件的教程 。很可能你會被引用到java.sun.com。

1

下面是我在另一條評論中承諾的代碼......這不是我記得的,但它可能會讓你開始。

本質上你調用:String fileName = FileUtils.getFileName(Main.class,「foo.txt」);

它會發現該文件在磁盤或JAR文件中。如果它在JAR文件中,則將其提取到臨時目錄。然後,您可以使用「新文件(文件名)」來打開該文件,無論以前它在哪裏,都將在磁盤上。

我會做的是看看getFile方法,看看你可以用JAR文件做什麼來迭代它的內容,並找到給定目錄中的文件。

就像我說的,不完全是你想要的,但確實爲你做了很多最初的工作。

import java.io.Closeable; 
import java.io.File; 
import java.io.FileNotFoundException; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.io.UnsupportedEncodingException; 
import java.net.URI; 
import java.net.URISyntaxException; 
import java.net.URL; 
import java.net.URLDecoder; 
import java.security.CodeSource; 
import java.security.ProtectionDomain; 
import java.util.zip.ZipEntry; 
import java.util.zip.ZipException; 
import java.util.zip.ZipFile; 


public class FileUtils 
{ 
    public static String getFileName(final Class<?> owner, 
            final String name) 
     throws URISyntaxException, 
       ZipException, 
       IOException 
    { 
     String fileName; 
     final URI uri; 

     try 
     { 
      final String external; 
      final String decoded; 
      final int pos; 

      uri  = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner); 
      external = uri.toURL().toExternalForm(); 
      decoded = external; // URLDecoder.decode(external, "UTF-8"); 
      pos  = decoded.indexOf(":/"); 
      fileName = decoded.substring(pos + 1); 
     } 
     catch(final FileNotFoundException ex) 
     { 
      fileName = null; 
     } 

     if(fileName == null || !(new File(fileName).exists())) 
     { 
      fileName = getFileNameX(owner, name); 
     } 

     return (fileName); 
    } 

    private static String getFileNameX(final Class<?> clazz, final String name) 
     throws UnsupportedEncodingException 
    { 
     final URL url; 
     final String fileName; 

     url = clazz.getResource(name); 

     if(url == null) 
     { 
      fileName = name; 
     } 
     else 
     { 
      final String decoded; 
      final int pos; 

      decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8"); 
      pos  = decoded.indexOf(":/"); 
      fileName = decoded.substring(pos + 1); 
     } 

     return (fileName); 
    } 

    private static URI getResourceAsURI(final String resourceName, 
             final Class<?> clazz) 
     throws URISyntaxException, 
       ZipException, 
       IOException 
    { 
     final URI uri; 
     final URI resourceURI; 

     uri   = getJarURI(clazz); 
     resourceURI = getFile(uri, resourceName); 

     return (resourceURI); 
    } 

    private static URI getJarURI(final Class<?> clazz) 
     throws URISyntaxException 
    { 
     final ProtectionDomain domain; 
     final CodeSource  source; 
     final URL    url; 
     final URI    uri; 

     domain = clazz.getProtectionDomain(); 
     source = domain.getCodeSource(); 
     url = source.getLocation(); 
     uri = url.toURI(); 

     return (uri); 
    } 

    private static URI getFile(final URI where, 
           final String fileName) 
     throws ZipException, 
       IOException 
    { 
     final File location; 
     final URI fileURI; 

     location = new File(where); 

     // not in a JAR, just return the path on disk 
     if(location.isDirectory()) 
     { 
      fileURI = URI.create(where.toString() + fileName); 
     } 
     else 
     { 
      final ZipFile zipFile; 

      zipFile = new ZipFile(location); 

      try 
      { 
       fileURI = extract(zipFile, fileName); 
      } 
      finally 
      { 
       zipFile.close(); 
      } 
     } 

     return (fileURI); 
    } 

    private static URI extract(final ZipFile zipFile, 
           final String fileName) 
     throws IOException 
    { 
     final File   tempFile; 
     final ZipEntry  entry; 
     final InputStream zipStream; 
     OutputStream  fileStream; 

     tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis())); 
     tempFile.deleteOnExit(); 
     entry = zipFile.getEntry(fileName); 

     if(entry == null) 
     { 
      throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName()); 
     } 

     zipStream = zipFile.getInputStream(entry); 
     fileStream = null; 

     try 
     { 
      final byte[] buf; 
      int   i; 

      fileStream = new FileOutputStream(tempFile); 
      buf  = new byte[1024]; 
      i   = 0; 

      while((i = zipStream.read(buf)) != -1) 
      { 
       fileStream.write(buf, 0, i); 
      } 
     } 
     finally 
     { 
      close(zipStream); 
      close(fileStream); 
     } 

     return (tempFile.toURI()); 
    } 

    private static void close(final Closeable stream) 
    { 
     if(stream != null) 
     { 
      try 
      { 
       stream.close(); 
      } 
      catch(final IOException ex) 
      { 
       ex.printStackTrace(); 
      } 
     } 
    } 
} 

編輯:

對不起,我沒有時間來對這一權利的工作,現在(如果我得到一些我會做到這一點並張貼在這裏的代碼)。這就是我會做,雖然:

  1. 看那ZipFile類,並使用entries()方法來發現所有的文件/目錄中的zip文件。
  2. ZipEntry有一個isDirectory()方法,您可以使用它來弄清楚它是什麼。
  3. 我認爲我發佈在this answer中的代碼將爲您提供一種方法來選擇一個臨時目錄來提取內容。
  4. 我認爲我發佈在this answer的代碼可以幫助將ZipEntry內容複製到文件系統。
  5. 一旦這些項目在文件系統上,您已經擁有的用於迭代目錄的代碼仍然可以工作。您可以在上面的代碼中爲FileUtils類添加一個新方法,並能夠像現在這樣查找所有文件。

有可能是一個更好的方法來做到這一點,但我的頭頂我認爲這將工作。

+0

那麼,我附加到我的答案的技術有什麼問題? :/ – Martin 2010-03-07 18:02:31

+0

1)我沒有看到它(我只是醒了!) 2)不會返回一個奇怪的URL與JAR!在其中,你不能打開一個文件? – TofuBeer 2010-03-07 18:13:15

+0

恐怕這超出了我對Java Jars文件的理解,你能否給我多一點幫助?可能是 – Martin 2010-03-07 21:49:37