【问题标题】:Save to external text-file from runnable jar从可运行 jar 保存到外部文本文件
【发布时间】:2020-07-13 14:08:22
【问题描述】:

我无法让我的可运行 jar 文件写入外部文本文件。我的意图是将数据存储在与可运行 jar 位于同一文件夹中的文本文件中(不在 jar 内);每行是一个数据集,新数据集附加在现有文件的末尾。 当我从 Eclipse 运行代码时,我尝试了几种不同的方法,它们都可以完美运行,但是一旦将其导出到可运行的 jar(也通过 Eclipse),它就不再更改文本文件。

这是我尝试过的事情:

  1. OutputStreamWriter

     public void writeData(String dataset) {
      try {      
        URL               url = getClass().getClassLoader().getResource("datasets.txt");
        OutputStream       os = new FileOutputStream(url.getFile(), true);
        OutputStreamWriter ow = new OutputStreamWriter(os);
    
        String line = "\n" + dataset; 
        ow.append(line);
        ow.close();
        os.close();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    
  2. 缓冲写入器

    public void writeData(String dataset) {
      try {
         URL           fileUrl = getClass().getClassLoader().getResource("datasets.txt")
         BufferedWriter writer = new BufferedWriter(new FileWriter(fileUrl.getPath(), true));
    
         writer.newLine(); 
         writer.write(dataset);
         writer.close();
    
       } catch (IOException e) {
         e.printStackTrace();
       }
     }
    
  3. 文件编写器

    public void writeData(String dataset) {   
      try {
        URL              url = getClass().getClassLoader().getResource("datasets.txt");
        FileOutputStream fos = new FileOutputStream(url.getFile(), true);
        FileWriter       out = new FileWriter(getFilePath(), true);
    
        out.append(dataset);
        out.close();
        fos.close();
      }  catch (IOException e) {
        e.printStackTrace();
      }
    }
    

一开始读取文件也给我带来了一些麻烦,但我让它与 InputStreamReader 一起工作,添加代码以防万一

private void readData() {
    InputStream       is = getClass().getClassLoader().getResourceAsStream("datasets.txt");
    InputStreamReader fr = new InputStreamReader(is);
    BufferedReader    br = new BufferedReader(fr);

    String line = null;
    while((line = br.readLine())!= null) {      
        dataVec.add(dataset); ...

我以前从来没有做过这样的事情,所以我很感激任何提示为什么这些方法不起作用或任何可能有帮助的提示,在此先感谢!

编辑: 根据我得到的关于为什么我的方法不起作用的解释,我决定实现一个文件选择器以允许用户选择他们想要使用的文件,而不是尝试使用相对于 jar 位置的固定文件。这样我就避免了必须找到相对路径的麻烦,并且可以选择处理包含不同数据集的多个单独文件。

【问题讨论】:

    标签: java file executable-jar


    【解决方案1】:

    这里的各种混乱:

    1. getResourcegetResourceAsStream 无法写入。您不能将这些转换为文件并祈祷您可以;资源是抽象的概念;具体来说,绝对是对可写性做出零承诺的抽象概念。一个简单的例子:通常'在部署',java代码在jar文件中,你不能以这种方式写入jar文件,你通常不想想要写入jar文件,甚至如果你这样做了,正确的安全设置往往会导致进程无法写入自己的 jar 文件,因此整个练习注定要失败。你不用这些。完全没有。

    2. '写到 jar 所在的同一个地方'一般是可疑的。为什么?在大约 1990 年的 Windows 上,这非常普遍,但它从来都不是在任何不在 DOS/Windows/CPM 行/MacOS 行中的操作系统上编写每个用户文件的好地方,而 1980 年代早已过去了经过。十多年来,它也不是 Windows 上特别常见的模型。相反,您将写入例如用户的 Documents 文件夹。该模型本身较差:写入可执行代码所在的相同目录意味着您可以写入代码,并且通常等待让您的盒子 p0wned,这就是操作系统成群结队地放弃此模型的原因。

    3. 如果您必须写入 jar 所在的同一文件夹,那么,这假定您的代码必然总是作为 jar 运行,这是在源文件中编码的奇怪假设。如果它不是 jar,比如在 eclipse 中调试时怎么办?在托管您的类文件的类路径条目旁边,因此,对于您的普通 Eclipse 项目~/workspace/projname,因为那是包含~/workspace/projname/bin 的目录,这是编译的类文件所在的位置?好的,你可以这样做。但你不想这样做(见第 1 点和第 2 点)。如果这些类是从网络中获取的、动态生成的,或者来自没有“源类路径条目是 ”概念的类加载器,该怎么办? - 只是祈祷你的代码永远不会在这种情况下部署?我至少会提供一个基于-D 的替代选项(您可以使用System.getProperty 阅读,因此,在您的java 代码String overrideLocation = System.getProperty("islandersproject.homedir"); 中并启动您的应用程序:java -Dislandersproject.homedir=/Users/islander/documents -jar islandersproject.jar

    好的,那我该怎么做呢?

    好吧,我说你可以。但这并不容易。

    对于任何给定的类,您都可以使用此构造获取加载它的位置:

    ClassName.class.getResource("ClassName.class").toString()

    只要有问题的类不是内部类,就可以。例如:

    System.out.println(String.class.getResource("String.class").toString()) - 试试看。

    你得到的字符串可以是任何东西。 IF 它是一个文件(例如,如果类是 /Users/islander/workspace/islandproject/bin/com/foo/island/islandproject/Island.class,你会得到那个字符串,file:// 加在前面。如果是 jar,你会得到类似:jar:file://Users/islander/blabla/islanderproject.jar!com/foo/island/islandproject/Island.class - 如果它是 jmod,它以 jmod: 开头(在 JDK11 或 14 上的 String 上运行它以查看它的运行情况),如果它是网络或动态生成,它将更加奇特。

    如果你真的很确定要这样做,请解析字符串。

    请注意,'.' (当前工作目录)绝不保证是正确的;如果你在windows的命令行上运行,例如:

    C:
    CD \foobar
    java -jar d:\workspace\dist\islander.jar
    

    然后. 将是完全不相关的c:\foobar,因为那是你开始的工作目录。因此不太可能是正确的,即使你在测试时运气好(因为 eclipse 等会设置它当您从 eclipse 中启动应用程序时,您可以恢复到一个理智的地方)。

    【讨论】:

    • 正如我所说,我以前从未这样做过,而且 - 显然很愚蠢 - 假设“与 jar 所在的文件夹相同”将是最容易使用的位置。我非常喜欢从文本文件读取/写入的概念,我可以在程序外部轻松编辑,但我没有设置位置或方法,因为这主要是一个小程序,我希望用来比较一些数据集。你有没有机会指出我应该如何应该做这样的事情?
    • 呵呵,可惜有点乱。最省力、至少朝着正确方向前进的解决方案是使用用户的主目录 (System.getProperty("user.home")) - 但在大多数操作系统上,你真的应该得到挂在上面的文档文件夹。我不知道有什么方法可以做到这一点,除了硬编码每个主要操作系统的规则。这个小小的额外努力会走得很远:在Windows上,那个+文档。在 Mac 上.. 同样的事情。在其他地方,只要坚持 user.home。
    • 谢谢,那我试试看!
    猜你喜欢
    • 1970-01-01
    • 2011-09-18
    • 1970-01-01
    • 2014-07-25
    • 2015-12-23
    • 2010-10-02
    • 2013-08-08
    • 2013-06-08
    • 1970-01-01
    相关资源
    最近更新 更多