我正在写在Android的文字游戏。这是我的第一个应用程序,所以我的知识几乎是不存在的。
我想这样做的是利用JWI访问WordNet的字典。这需要指定的WordNet词典的文件路径。
从我读过,Android的资产是不是可以通过一个简单的文件路径,但什么JWI需要初始化WordNet的字典API是一个URL到字典文件的磁盘位置。
那么,什么是最好的行动过程?我应该在启动时的资产复制到一个已知的文件夹,在Android设备上?我想不出更好的办法,但似乎完全是愚蠢的我。
任何帮助感激地接受。
解决方案我有(然而,对于不机器人码头Web应用程序)同样的问题,并试图这两种方法,但没有成功:
JWNL.initialize(this.getClass().getClassLoader().getResourceAsStream("wordnet_properties.xml"); 字典= Dictionary.getInstance();下面它成功地加载wordnet_properties.xml但它不能访问其由属性文件指向词典中。
直接使用字典文件夹:
字符串DICTPATH =型号/ EN / WordNet中/词典/;
网址URL = this.getClass()getClassLoader()的getResource(DICTPATH)。
的System.out.println(+网址加载的WordNet);
字典=新RAMDictionary(URL,ILoadPolicy.NO_LOAD);
在这里我得到的词典网址是jar:file:/home/myusername/.m2/repository/package/1.0-SNAPSHOT/commons-1.0-SNAPSHOT.jar!/models/en/wordnet/dict/.然而WORDNET不接受罐子协议,并给我的错误:
java.lang.IllegalArgumentException:如果URL源必须使用文件协议
在edu.mit.jwi.data.FileProvider.toFile(FileProvider.java:693)
在edu.mit.jwi.data.FileProvider.open(FileProvider.java:304)
在edu.mit.jwi.DataSourceDictionary.open(DataSourceDictionary.java:92)
在edu.mit.jwi.RAMDictionary.open(RAMDictionary.java:216)
我的下一个调查将是创建一个子类来RAMDictionary或类似的东西,请告诉我,如果你发现了其间的解决方案。
PS:我只是写了开发者邮件寻求帮助后,我试图重写FileProvider使用资源,而不是,但是一两个小时后,我放弃了,因为code调用这么多其他的code表示也只适用于文件。我将让你最新的!
PPS:我收到答复从显影剂说是principially不可能的流,因为它们不提供随机访问是必要的。不过,他表示愿意执行解决方案来加载所有的内存,如果真的有必要,但会用掉约500 MB的,我想这是太多的Android应用程序,所以我想最好还是先把它解压。
PS:这是我的解包解决方案(如果您使用记录或删除他们,如果你不喜欢他们,你可以更换System.out.println语句与记录报表):
进口的java.io.File;
进口java.io.FileOutputStream中;
进口java.io.IOException异常;
进口的java.io.InputStream;
进口java.net.URISyntaxException;
进口的java.util.Enumeration;
进口java.util.jar.JarEntry;
进口java.util.jar.JarFile中;
/ **允许的WordNet从内部jar文件通过将其解压到一个临时目录中运行。** /
公共类WordNetUnpacker
{
静态最后字符串ID =178558556719; //尽量减少与现有目录干扰的机会
静态最后弦乐jarDir =型号/ EN /的WordNet /字典;
/ **如果是从一个罐子内运行,从罐子到一个临时目录解压的WordNet(如果尚未完成),并返回。
*如果不是从一个罐子里运行,只返回现有的WordNet目录。
* @see getUnpackedWordNetDir(类)* /
静态文件getUnpackedWordNetDir()抛出IOException异常
{返回getUnpackedWordNetDir(WordNetUnpacker.class);}
/ **如果是从一个罐子内运行,从罐子到一个临时目录解压的WordNet(如果尚未完成),并返回。
*如果不是从一个罐子里运行,只返回现有的WordNet目录。
*参数clazz所中的类加载器WordNet的资源被发现的类。
* @see getUnpackedWordNetDir()** /
静态文件getUnpackedWordNetDir(类clazz所)抛出IOException异常
{
字符串codeSource = clazz.getProtectionDomain()得到codeSource()的getLocation()getPath()。;
的System.out.println(getUnpackedWordNetDir:使用code源代码+ codeSource);
如果(!codeSource.endsWith(罐子))
{
的System.out.println(不是从瓶子运行,没有必要拆包);
尝试{返回新文件(WordNetUnpacker.class.getClassLoader()的getResource(jarDir).toURI());}
赶上(的URISyntaxException E){抛出新IOException异常(E);}
}
尝试(jar文件jar文件=新的JarFile(codeSource))
{
串tempDirString = System.getProperty(java.io.tmpdir);
如果(tempDirString == NULL){抛出新IOException异常(java.io.tmpdir未设定);}
文件TEMPDIR =新的文件(tempDirString);
如果(tempDir.exists()!){抛出新IOException异常(临时目录不存在);}
(!tempDir.isDirectory()){如果抛出IOException异常新(临时目录是一个文件,不是一个目录);}
文件wordNetDir =新的文件(tempDirString +/+的WordNet+ ID);
wordNetDir.mkdir();
的System.out.println(解包jar文件+ jarFile.getName());
copyResourcesToDirectory(jar文件,jarDir,wordNetDir.getAbsolutePath());
返回wordNetDir;
}
}
/ **复制从一个jar文件到外部目录的目录。 A HREF =http://stackoverflow.com/a/19859453/398963>堆栈溢出<来自以下的复制/ a取代。 * /
公共静态无效copyResourcesToDirectory(jar文件fromJar,字符串jarDir,字符串DESTDIR)抛出IOException异常
{
INT copyCount = 0;
对于(枚举<的JarEntry>输入= fromJar.entries(); entries.hasMoreElements();)
{
的JarEntry条目= entries.nextElement();
如果(!entry.getName()包含(模型))继续;
如果(entry.getName()startsWith(jarDir)及。&安培;!entry.isDirectory()){
copyCount ++;
文件DEST =新的文件(DESTDIR +/+ entry.getName()子(jarDir.length()+ 1));
文件的父= dest.getParentFile();
如果(父!= NULL){
parent.mkdirs();
}
FileOutputStream中出=新的FileOutputStream(DEST);
InputStream的时间= fromJar.getInputStream(项);
尝试 {
byte []的缓冲区=新的字节[8 * 1024];
INT S = 0;
而((S = in.read(缓冲液))大于0){
out.write(缓冲液,O,S);
}
}赶上(IOException异常E){
抛出新IOException异常(,E无法从JAR文件复制资产);
} 最后 {
尝试 {
附寄();
}赶上(IOException异常忽略){}
尝试 {
out.close();
}赶上(IOException异常忽略){}
}
}
}
如果(copyCount == 0)的System.out.println(警告:没有文件复制);
}
}
I'm writing a word game in Android. It's my first app so my knowledge is almost non-existent.
What I would like to do is use JWI to access the WordNet dictionary. This requires specifying the WordNet dictionary's file path.
From what I've read, Android "assets" are not available via a simple file path, but what JWI requires to initialize the WordNet dictionary API is a URL to the disk location of the dictionary files.
So, what is the best course of action? Should I copy the assets at startup-time into a known folder on the android device? I can't think of a better way but that seems entirely stupid to me.
Any help gratefully received.
解决方案I have the same problem (for a jetty webapp however and not android) and tried those two approaches, however unsuccessfully:
JWNL.initialize(this.getClass().getClassLoader().getResourceAsStream("wordnet_properties.xml");
dict = Dictionary.getInstance();
Here it successfully loads wordnet_properties.xml but it cannot access the dictionary which is pointed to by the properties file.
Using the dictionary folder directly:
String dictPath = "models/en/wordnet/dict/";
URL url = this.getClass().getClassLoader().getResource(dictPath);
System.out.println("loading wordnet from "+url);
dict = new RAMDictionary(url, ILoadPolicy.NO_LOAD);
Here I get the dictionary URL to be jar:file:/home/myusername/.m2/repository/package/1.0-SNAPSHOT/commons-1.0-SNAPSHOT.jar!/models/en/wordnet/dict/
. WordNet however doesn't accept the jar protocol and gives me the error:
java.lang.IllegalArgumentException: URL source must use 'file' protocol
at edu.mit.jwi.data.FileProvider.toFile(FileProvider.java:693)
at edu.mit.jwi.data.FileProvider.open(FileProvider.java:304)
at edu.mit.jwi.DataSourceDictionary.open(DataSourceDictionary.java:92)
at edu.mit.jwi.RAMDictionary.open(RAMDictionary.java:216)
My next investigation will be to create a subclass to RAMDictionary or something similar, please tell me if you have found a solution in the meantime.
P.S.: I just wrote the developer a mail asking for help after I tried to rewrite the FileProvider to use resources instead but after one or two hours I gave up because the code calls so much other code that also only works with files. I will keep you up to date!
P.P.S.: I received an answer from the developer saying that it is principially not possible with streams because they don't offer random access which is necessary. However, he offered to implement a solution to load it all in RAM, if really necessary, but that would use up about 500 MB and I guess that is too much for android apps so I guess it is still best to unpack it somewhere.
P.S.: Here is my unpacking solution (you can replace the System.out.println statements with logger statements if you use logging or remove them if you don't like them):
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/** Allows WordNet to be run from within a jar file by unpacking it to a temporary directory.**/
public class WordNetUnpacker
{
static final String ID = "178558556719"; // minimize the chance of interfering with an existing directory
static final String jarDir = "models/en/wordnet/dict";
/**If running from within a jar, unpack wordnet from the jar to a temp directory (if not already done) and return that.
* If not running from a jar, just return the existing wordnet directory.
* @see getUnpackedWordNetDir(Class)*/
static File getUnpackedWordNetDir() throws IOException
{return getUnpackedWordNetDir(WordNetUnpacker.class);}
/**If running from within a jar, unpack wordnet from the jar to a temp directory (if not already done) and return that.
* If not running from a jar, just return the existing wordnet directory.
* @param clazz the class in whose classloader the wordnet resources are found.
* @see getUnpackedWordNetDir()**/
static File getUnpackedWordNetDir(Class clazz) throws IOException
{
String codeSource = clazz.getProtectionDomain().getCodeSource().getLocation().getPath();
System.out.println("getUnpackedWordNetDir: using code source "+codeSource);
if(!codeSource.endsWith(".jar"))
{
System.out.println("not running from jar, no unpacking necessary");
try{return new File(WordNetUnpacker.class.getClassLoader().getResource(jarDir).toURI());}
catch (URISyntaxException e) {throw new IOException(e);}
}
try(JarFile jarFile = new JarFile(codeSource))
{
String tempDirString = System.getProperty("java.io.tmpdir");
if(tempDirString==null) {throw new IOException("java.io.tmpdir not set");}
File tempDir = new File(tempDirString);
if(!tempDir.exists()) {throw new IOException("temporary directory does not exist");}
if(!tempDir.isDirectory()) {throw new IOException("temporary directory is a file, not a directory ");}
File wordNetDir = new File(tempDirString+'/'+"wordnet"+ID);
wordNetDir.mkdir();
System.out.println("unpacking jarfile "+jarFile.getName());
copyResourcesToDirectory(jarFile, jarDir, wordNetDir.getAbsolutePath());
return wordNetDir;
}
}
/** Copies a directory from a jar file to an external directory. Copied from <a href="http://stackoverflow.com/a/19859453/398963">Stack Overflow</a>. */
public static void copyResourcesToDirectory(JarFile fromJar, String jarDir, String destDir) throws IOException
{
int copyCount = 0;
for (Enumeration<JarEntry> entries = fromJar.entries(); entries.hasMoreElements();)
{
JarEntry entry = entries.nextElement();
if(!entry.getName().contains("models")) continue;
if (entry.getName().startsWith(jarDir) && !entry.isDirectory()) {
copyCount++;
File dest = new File(destDir + "/" + entry.getName().substring(jarDir.length() + 1));
File parent = dest.getParentFile();
if (parent != null) {
parent.mkdirs();
}
FileOutputStream out = new FileOutputStream(dest);
InputStream in = fromJar.getInputStream(entry);
try {
byte[] buffer = new byte[8 * 1024];
int s = 0;
while ((s = in.read(buffer)) > 0) {
out.write(buffer, 0, s);
}
} catch (IOException e) {
throw new IOException("Could not copy asset from jar file", e);
} finally {
try {
in.close();
} catch (IOException ignored) {}
try {
out.close();
} catch (IOException ignored) {}
}
}
}
if(copyCount==0) System.out.println("Warning: No files copied!");
}
}