web-dev-qa-db-ja.com

プログラムでJavaのresources / sourceフォルダーにファイルを作成しますか?

2つのリソースフォルダーがあります。

src-ここに私の.Javaファイルがあります

リソース-これは、フォルダー(パッケージ)に整理されたリソースファイル(画像、.properties)です。

そのリソースフォルダーに別の.propertiesファイルをプログラムで追加する方法はありますか?

私はこのようなものを試しました:

public static void savePropertiesToFile(Properties properties, File propertiesFile) throws IOException {
        FileOutputStream out = new FileOutputStream(propertiesFile);
        properties.store(out, null);
        out.close();
    }

それが作成される前:

new File("/folderInResources/newProperties.properties");

しかし、ファイルシステム上でそのパスを探します。どのようにすれば、リソースフォルダーを強制的に検索できますか?

[〜#〜] edit [〜#〜]:それが何であるかについてお話させてください。 GUIアプリケーションがあり、2つの言語(リソースフォルダー内の2つの.propertiesファイル)をサポートしています。ここで、ユーザーがアプリケーションを簡単に翻訳できるオプションを追加しました。ユーザーが終了したら、新しい.propertiesをディスクの隠しフォルダーに保存し、そこから読み取ります。しかし、現在の言語(resourcesフォルダー)の横に新しい.propertiesファイル(新しい言語)を保存できることを望んでいました。私は、ディスクからリソースを読み込む方法と、リソースフォルダーのデフォルトのリソースを読み込む方法を知っている静的なメッセージクラスを持っています。しかし、ユーザーがこの.jarファイルを他のマシンで取得した場合、それらは.jarファイル内ではなく、そのコンピューターのディスク上にあるため、その新しい言語はありません。

15
vale4674

他の人が述べたように、リソースはClassLoaderを通じて取得されます。しかし、現在の2つの対応で強調できなかったのは、次の点です。

  • ClassLoadersはabstractクラスおよびその他のリソースを取得するプロセスを意図しています。リソースは、ファイルシステム内のファイルである必要はありません。これは、リモートURL、または_Java.lang.ClassLoader_を拡張することによってユーザーまたは他の誰かが実装する可能性のあるすべてのものにすることができます。
  • ClassLoadersは、子/親の委任チェーンに存在します。 ClassLoaderの通常の動作は、最初に親からリソースを取得しようとし、次にそれ自体のリソースを検索することですが、一部のクラスローダーは逆の順序で実行されます(たとえば、サーブレットコンテナー内)。いずれにせよ、入れたいものを取得するクラスローダーの場所を特定する必要があります。さらに、その上または下にある別のクラスローダーがクライアントコードのリソース要求を「盗む」可能性があります。
  • Lionel Portが指摘するように、単一のClassLoaderでも、そこからデータをロードする場所が複数ある場合があります。
  • ClassLoadersは、クラスをロードするために使用されます。プログラムがクラスのロード元の場所にファイルを書き込むことができる場合、ユーザーが実行中のアプリケーションにコードを挿入できる可能性があるため、これは簡単にセキュリティリスクになる可能性があります。

ショートバージョン:しないでください。 「リソースを取得できるリソースのようなもののリポジトリ」という概念のためのより抽象的なインターフェースと、「リソースを取得できるが、追加できるリソースのようなもののリポジトリ」のサブインターフェースを記述します。後者は、両方ともClassLoader.getContextClassLoader().getResource()を使用して(クラスパスを検索するため)実装し、それが失敗した場合は、他のメカニズムを使用して、プログラムが特定の場所から追加したものを取得します。

7
Luis Casillas

コンパイルされたサブフォルダーのメインプロジェクトフォルダー( "/ target/classes"、 "target/test-classes")を切り取り、プロジェクトフォルダーを再構築するための基本的なパスを取得します。

import Java.io.File;
import Java.io.IOException;
import Java.net.URISyntaxException;

public class SubfolderCreator {

public static void main(String... args) throws URISyntaxException, IOException {
    File newResourceFolder = createResourceSubFolder("newFolder");
}

private static File createResourceSubFolder(String folderName) throws URISyntaxException, IOException {
    Java.net.URL url = SubfolderCreator.class.getResource("/EXISTING_SUBFOLDER/");
    File fullPathToSubfolder = new File(url.toURI()).getAbsoluteFile();
    String projectFolder = fullPathToSubfolder.getAbsolutePath().split("target")[0];
    File testResultsFolder = new File(projectFolder + "src/test/resources/" + folderName);
    if (!testResultsFolder.exists()) {
        testResultsFolder.mkdir();
    }
    return testResultsFolder;
}
}
1
Emiel Ackermann

Java 8ソリューション

 Path source = Paths.get(this.getClass().getResource("/").getPath());
        Path newFolder = Paths.get(source.toAbsolutePath() + "/newFolder/");
        Files.createDirectories(newFolder);

これにより、リソースフォルダに新しいフォルダが確実に作成されます。しかし、ターゲットランタイムに新しいフォルダが見つかります。

これは、ProjectName/target/test-classes/newFolderになります。このコードをテストケースで実行している場合。それ以外の場合は、ターゲット/クラスになります

Src/resourcesで新しいフォルダーを見つけようとしないでください。確かにtarget/test-classesまたはtarget/classesにあります。

0
RohitKumar

問題は、クラスパスに複数のルートディレクトリが含まれている可能性があるため、既存のファイルまたはディレクトリがないと、格納するルートディレクトリを区別するのが難しいことです。

既存のファイルがロードされている場合。

File existingFile = ...;
File parentDirectory = existingFile.getParentFile();
new File(parentDirectory, "newProperties.properties");

それ以外の場合は、リソースディレクトリで一意であることがわかっているディレクトリのハンドルを取得してみてください。 (これが機能するかどうかはわかりません)

URL url = this.getClass().getResource("/parentDirectory");
File parentDirectory = new File(new URI(url.toString()));
new File(parentDirectory, "newProperties.properties");
0
Lionel Port

次のコードは、クラスファイルとともにclassesディレクトリに書き込みます。

他の人が指摘したように、クラスファイルの上書きには注意してください。新しいファイルを別のディレクトリに配置するのが最善です。ただし、そのディレクトリはすでに存在している必要があります。それを作成するには、ソースのリソース内にサブディレクトリを作成します。空のファイルが含まれている可能性があります。例えば ​​src\main\resources\dir\empty.txt

public class WriteResource {
    public static void main(String[] args) throws FileNotFoundException {
        String thing = "Text to write to the file";
        String dir = WriteResource.class.getResource("/").getFile();
        //String dir = WriteResource.class.getResource("/dir").getFile();
        OutputStream os = new FileOutputStream(dir + "/file.txt");
        final PrintStream printStream = new PrintStream(os);
        printStream.println(thing);
        printStream.close();
    }
}

これでうまくいきますが、厳密に制御された環境の外でこれを展開することに不安を感じます。許可されていない人がclassesディレクトリに書き込むという考えはあまり好きではありません!

0
Steve Pitchers

リソースはクラスローダーを介してロードされ、デフォルトのクラスローダーは大量にキャッシュします。

非静的ファイルシステムからリソースを読み取るには、必要な動作を備えた独自のクラスローダーが必要です。