在Android应用程序访问WordNet的字典文件字典、应用程序、文件、Android

2023-09-05 23:41:55 作者:單身yě不寂寞

我正在写在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)
 
Android移动应用开发 第3版 卷Ⅰ基础篇 ShaneConder,LaurenDarcey PDF扫描版 android移动应用程序开发第三版 Android文档类资源 CSDN下载

我的下一个调查将是创建一个子类来RAMDictionary或类似的东西,请告诉我,如果你发现了其间的解决方案。

PS:我只是写了开发者邮件寻求帮助后,我试图重写FileProvider使用资源,而不是,但是一两个小时后,我放弃了,因为code调用这么多其他的code表示也只适用于文件。我将让你最新的!

PPS:我收到答复从显影剂说是principially不可能的流,因为它们不提供随机访问是必要的。不过,他表示愿意执行解决方案来加载所有的内存,如果真的有必要,但会用掉约500 MB的,我想这是太多的Andr​​oid应用程序,所以我想最好还是先把它解压。

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).to​​URI());}
            赶上(的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 =htt​​p://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!");
    }
}