it-swarm.com.de

Ruft eine Liste der Ressourcen aus dem Klassenpfadverzeichnis ab

Ich suche nach einer Möglichkeit, eine Liste aller Ressourcennamen aus einem bestimmten Klassenpfadverzeichnis abzurufen, etwa einer Methode List<String> getResourceNames (String directoryName).

Angenommen, ein Klassenpfadverzeichnis x/y/z Enthält Dateien a.html, b.html, c.html Und ein Unterverzeichnis d, getResourceNames("x/y/z") sollte einen List<String> mit den folgenden Zeichenfolgen zurückgeben: ['a.html', 'b.html', 'c.html', 'd'].

Es sollte sowohl für Ressourcen im Dateisystem als auch für Gläser funktionieren.

Ich weiß, dass ich mit Files, JarFiles und URLs einen kurzen Ausschnitt schreiben kann, aber ich möchte das Rad nicht neu erfinden. Meine Frage ist, angesichts der vorhandenen öffentlich zugänglichen Bibliotheken, wie man getResourceNames am schnellsten implementiert. Spring und Apache Commons Stacks sind beide möglich.

219
viaclectic

Benutzerdefinierter Scanner

Implementieren Sie Ihren eigenen Scanner. Zum Beispiel:

private List<String> getResourceFiles(String path) throws IOException {
    List<String> filenames = new ArrayList<>();

    try (
            InputStream in = getResourceAsStream(path);
            BufferedReader br = new BufferedReader(new InputStreamReader(in))) {
        String resource;

        while ((resource = br.readLine()) != null) {
            filenames.add(resource);
        }
    }

    return filenames;
}

private InputStream getResourceAsStream(String resource) {
    final InputStream in
            = getContextClassLoader().getResourceAsStream(resource);

    return in == null ? getClass().getResourceAsStream(resource) : in;
}

private ClassLoader getContextClassLoader() {
    return Thread.currentThread().getContextClassLoader();
}

Spring Framework

Verwenden Sie PathMatchingResourcePatternResolver aus Spring Framework.

Ronmamo Reflexionen

Die anderen Techniken sind zur Laufzeit möglicherweise langsam, wenn große CLASSPATH-Werte vorliegen. Eine schnellere Lösung ist die Verwendung von ronmamo's Reflections API , das die Suche zur Kompilierungszeit vorkompiliert.

154
iirekm

Hier ist der Code
Quelle : forums.devx.com/showthread.php?t=153784

import Java.io.File;
import Java.io.IOException;
import Java.util.ArrayList;
import Java.util.Collection;
import Java.util.Enumeration;
import Java.util.regex.Pattern;
import Java.util.Zip.ZipEntry;
import Java.util.Zip.ZipException;
import Java.util.Zip.ZipFile;

/**
 * list resources available from the classpath @ *
 */
public class ResourceList{

    /**
     * for all elements of Java.class.path get a Collection of resources Pattern
     * pattern = Pattern.compile(".*"); gets all resources
     * 
     * @param pattern
     *            the pattern to match
     * @return the resources in the order they are found
     */
    public static Collection<String> getResources(
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final String classPath = System.getProperty("Java.class.path", ".");
        final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
        for(final String element : classPathElements){
            retval.addAll(getResources(element, pattern));
        }
        return retval;
    }

    private static Collection<String> getResources(
        final String element,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File file = new File(element);
        if(file.isDirectory()){
            retval.addAll(getResourcesFromDirectory(file, pattern));
        } else{
            retval.addAll(getResourcesFromJarFile(file, pattern));
        }
        return retval;
    }

    private static Collection<String> getResourcesFromJarFile(
        final File file,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        ZipFile zf;
        try{
            zf = new ZipFile(file);
        } catch(final ZipException e){
            throw new Error(e);
        } catch(final IOException e){
            throw new Error(e);
        }
        final Enumeration e = zf.entries();
        while(e.hasMoreElements()){
            final ZipEntry ze = (ZipEntry) e.nextElement();
            final String fileName = ze.getName();
            final boolean accept = pattern.matcher(fileName).matches();
            if(accept){
                retval.add(fileName);
            }
        }
        try{
            zf.close();
        } catch(final IOException e1){
            throw new Error(e1);
        }
        return retval;
    }

    private static Collection<String> getResourcesFromDirectory(
        final File directory,
        final Pattern pattern){
        final ArrayList<String> retval = new ArrayList<String>();
        final File[] fileList = directory.listFiles();
        for(final File file : fileList){
            if(file.isDirectory()){
                retval.addAll(getResourcesFromDirectory(file, pattern));
            } else{
                try{
                    final String fileName = file.getCanonicalPath();
                    final boolean accept = pattern.matcher(fileName).matches();
                    if(accept){
                        retval.add(fileName);
                    }
                } catch(final IOException e){
                    throw new Error(e);
                }
            }
        }
        return retval;
    }

    /**
     * list the resources that match args[0]
     * 
     * @param args
     *            args[0] is the pattern to match, or list all resources if
     *            there are no args
     */
    public static void main(final String[] args){
        Pattern pattern;
        if(args.length < 1){
            pattern = Pattern.compile(".*");
        } else{
            pattern = Pattern.compile(args[0]);
        }
        final Collection<String> list = ResourceList.getResources(pattern);
        for(final String name : list){
            System.out.println(name);
        }
    }
}  

Wenn Sie Spring verwenden, schauen Sie sich PathMatchingResourcePatternResolver an

47
Jigar Joshi

Verwenden von Google Reflections:

Holen Sie sich alles auf den Klassenweg:

Reflections reflections = new Reflections(null, new ResourcesScanner());
Set<String> resourceList = reflections.getResources(x -> true);

Ein weiteres Beispiel - holen Sie sich alle Dateien mit der Endung .csv von some.package:

Reflections reflections = new Reflections("some.package", new ResourcesScanner());
Set<String> fileNames = reflections.getResources(Pattern.compile(".*\\.csv"));
18
NS du Toit

Wenn Sie Apache commonsIO verwenden, können Sie für das Dateisystem Folgendes verwenden (optional mit Erweiterungsfilter):

Collection<File> files = FileUtils.listFiles(new File("directory/"), null, false);

und für Ressourcen/Klassenpfad:

List<String> files = IOUtils.readLines(MyClass.class.getClassLoader().getResourceAsStream("directory/"), Charsets.UTF_8);

Wenn Sie nicht wissen, ob sich "directoy /" im Dateisystem oder in den Ressourcen befindet, können Sie eine hinzufügen

if (new File("directory/").isDirectory())

oder

if (MyClass.class.getClassLoader().getResource("directory/") != null)

vor den anrufen und beides in kombination nutzen ...

16
Rob

In Bezug auf den PathMatchingResourcePatternResolver wird im Code Folgendes benötigt:

@Autowired
ResourcePatternResolver resourceResolver;

public void getResources() {
  resourceResolver.getResources("classpath:config/*.xml");
}
11
Pavel Kotlov

Das Spring framework 's PathMatchingResourcePatternResolver ist wirklich großartig für diese Dinge:

private Resource[] getXMLResources() throws IOException
{
    ClassLoader classLoader = MethodHandles.lookup().getClass().getClassLoader();
    PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(classLoader);

    return resolver.getResources("classpath:x/y/z/*.xml");
}

Maven-Abhängigkeit:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>LATEST</version>
</dependency>
5
BullyWiiPlaza

Verwendete eine Kombination aus Robs Antwort.

final String resourceDir = "resourceDirectory/";
List<String> files = IOUtils.readLines(Thread.currentThread.getClass().getClassLoader().getResourceAsStream(resourceDir), Charsets.UTF_8);

for(String f : files){
  String data= IOUtils.toString(Thread.currentThread.getClass().getClassLoader().getResourceAsStream(resourceDir + f));
  ....process data
}
5
Trevor

Dies sollte funktionieren (wenn der Frühling keine Option ist):

public static List<String> getFilenamesForDirnameFromCP(String directoryName) throws URISyntaxException, UnsupportedEncodingException, IOException {
    List<String> filenames = new ArrayList<>();

    URL url = Thread.currentThread().getContextClassLoader().getResource(directoryName);
    if (url != null) {
        if (url.getProtocol().equals("file")) {
            File file = Paths.get(url.toURI()).toFile();
            if (file != null) {
                File[] files = file.listFiles();
                if (files != null) {
                    for (File filename : files) {
                        filenames.add(filename.toString());
                    }
                }
            }
        } else if (url.getProtocol().equals("jar")) {
            String dirname = directoryName + "/";
            String path = url.getPath();
            String jarPath = path.substring(5, path.indexOf("!"));
            try (JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()))) {
                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String name = entry.getName();
                    if (name.startsWith(dirname) && !dirname.equals(name)) {
                        URL resource = Thread.currentThread().getContextClassLoader().getResource(name);
                        filenames.add(resource.toString());
                    }
                }
            }
        }
    }
    return filenames;
}
3
fl0w

Mit Spring ist es einfach. Sei es eine Datei oder ein Ordner oder sogar mehrere Dateien, es besteht die Möglichkeit, dass Sie dies per Injektion tun können.

Dieses Beispiel zeigt das Einfügen mehrerer Dateien in x/y/z Mappe.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;

@Service
public class StackoverflowService {
    @Value("classpath:x/y/z/*")
    private Resource[] resources;

    public List<String> getResourceNames() {
        return Arrays.stream(resources)
                .map(Resource::getFilename)
                .collect(Collectors.toList());
    }
}

Es funktioniert sowohl für Ressourcen im Dateisystem als auch in JARs.

1
naXa

Keine der Antworten hat bei mir funktioniert, obwohl ich meine Ressourcen in Ressourcenordnern abgelegt habe und den obigen Antworten gefolgt bin. Was hat einen Trick gemacht war:

@Value("file:*/**/resources/**/schema/*.json")
private Resource[] resources;
0
kukis

Ich denke, Sie können den [Zip File System Provider] [1] nutzen, um dies zu erreichen. Bei Verwendung von FileSystems.newFileSystem Können Sie die Objekte in diesem Zip wie eine "normale" Datei behandeln.

In der verlinkten Dokumentation oben:

Geben Sie die Konfigurationsoptionen für das Zip-Dateisystem im Java.util.Map-Objekt an, das an die Methode FileSystems.newFileSystem Übergeben wird. Informationen zu den anbieterspezifischen Konfigurationseigenschaften für das Zip-Dateisystem finden Sie im Thema [Eigenschaften des Zip-Dateisystems] [2].

Sobald Sie eine Instanz eines Zip-Dateisystems haben, können Sie die Methoden der Klassen [Java.nio.file.FileSystem] [3] und [Java.nio.file.Path] [4] aufrufen, um Vorgänge wie Kopieren, Verschieben auszuführen und Umbenennen von Dateien sowie Ändern von Dateiattributen.

Die Dokumentation für das Modul jdk.zipfs In [Java 11-Status] [5]:

Der Zip-Dateisystemanbieter behandelt eine Zip- oder JAR-Datei als Dateisystem und bietet die Möglichkeit, den Inhalt der Datei zu bearbeiten. Der Zip-Dateisystemanbieter kann durch [FileSystems.newFileSystem] [6] erstellt werden, falls installiert.

Hier ist ein ausgedachtes Beispiel, das ich anhand Ihrer Beispielressourcen erstellt habe. Beachten Sie, dass ein .Zip Ein .jar Ist, aber Sie können Ihren Code anpassen, um stattdessen Klassenpfadressourcen zu verwenden:

Setup

cd /tmp
mkdir -p x/y/z
touch x/y/z/{a,b,c}.html
echo 'hello world' > x/y/z/d
Zip -r example.Zip x

Java

import Java.io.IOException;
import Java.net.URI;
import Java.nio.file.FileSystem;
import Java.nio.file.FileSystems;
import Java.nio.file.Files;
import Java.util.Collections;
import Java.util.stream.Collectors;

public class MkobitZipRead {

  public static void main(String[] args) throws IOException {
    final URI uri = URI.create("jar:file:/tmp/example.Zip");
    try (
        final FileSystem zipfs = FileSystems.newFileSystem(uri, Collections.emptyMap());
    ) {
      Files.walk(zipfs.getPath("/")).forEach(path -> System.out.println("Files in Zip:" + path));
      System.out.println("-----");
      final String manifest = Files.readAllLines(
          zipfs.getPath("x", "y", "z").resolve("d")
      ).stream().collect(Collectors.joining(System.lineSeparator()));
      System.out.println(manifest);
    }
  }

}

Ausgabe

Files in Zip:/
Files in Zip:/x/
Files in Zip:/x/y/
Files in Zip:/x/y/z/
Files in Zip:/x/y/z/c.html
Files in Zip:/x/y/z/b.html
Files in Zip:/x/y/z/a.html
Files in Zip:/x/y/z/d
-----
hello world
0
mkobit