2010-10-13 28 views
158

我正在尋找一種方法來獲取給定類路徑目錄中所有資源名稱的列表,如方法List<String> getResourceNames (String directoryName)從類路徑目錄獲取資源列表

例如,給定一個路徑目錄x/y/z包含文件a.htmlb.htmlc.html和子目錄dgetResourceNames("x/y/z")應該返回包含下列字符串的一個List<String>['a.html', 'b.html', 'c.html', 'd']

它應該適用於文件系統和罐子中的資源。

我知道我可以用File s,JarFile s和URL s寫一個快速片段,但我不想重新發明輪子。我的問題是,考慮到現有的公開庫,實施getResourceNames的最快方法是什麼? Spring和Apache Commons棧都是可行的。

+1

相關問題:http://stackoverflow.com/a/30149061/4102160 – Cfx 2015-05-10 08:08:27

回答

121

自定義掃描儀

實施您自己的掃描儀。例如:

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框架

使用PathMatchingResourcePatternResolver從Spring框架。

Ronmamo思考

的其他技術可能會在運行時巨大的CLASSPATH值緩慢。更快的解決方案是使用ronmamo的Reflections API,它在編譯時預編譯搜索。

+0

反射看起來像一個偉大的想法,但沒有IDE集成它有點限制。 – JBCP 2012-05-24 04:13:43

+7

如果使用Reflections,您實際上需要:'新的Reflections(「my.package」,新的ResourcesScanner())。getResources(pattern)' – zapp 2013-03-16 13:16:14

+8

當第一個解決方案從jar文件執行時,它是否工作?對我而言 - 事實並非如此。我可以通過這種方式讀取文件,但無法讀取目錄。 – 2016-10-06 12:28:12

44

下面是代碼
來源: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); 
     } 
    } 
} 

如果您在使用Spring看一看PathMatchingResourcePatternResolver

+3

提問者知道如何使用標準的java類來實現它,但他想知道他如何利用現有的(Spring,Apache Commons)庫。 – 2010-10-13 11:54:31

+2

'PathMatchingResourcePatternResolver'完成了訣竅。 – viaclectic 2010-10-13 12:24:56

+0

@Jeroen Rosenberg還有另一種方式給出最終被選中:) – 2010-10-13 12:26:16

14

如果你使用Apache commonsIO您可以使用文件系統(任選延伸過濾器):

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

和資源/類路徑:

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

如果你不知道「 directoy /「位於文件系統中或可添加的資源中

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

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

,並使用這兩種組合...

+14

文件!=資源 – djechlin 2013-12-13 21:27:19

+3

當然,資源可能不總是文件,但問題是關於源自文件/目錄的資源。因此,如果您想檢查不同的位置,請使用示例代碼如果你的資源中有一個config.xml文件用於某些默認配置,那麼應該可以加載外部config.xml,如果它存在的話... – Rob 2013-12-19 16:03:04

+1

爲什麼資源不是文件?資源是歸檔到zip檔案中的文件。那些被加載到內存中並以特定方式訪問,但我不明白他們爲什麼不是文件。任何不是'歸檔文件中的文件'的資源的實例? – 2017-05-18 07:20:23

5

所以在PathMatchingResourcePatternResolver而言,這是我們需要的代碼:

@Autowired 
ResourcePatternResolver resourceResolver; 

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

使用Rob的響應的組合。

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 
} 
10

使用谷歌的反思:

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

另一個示例:獲得所有文件的.csv擴展名從some.package

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

基於@rob的上面的信息,我創建了我向公衆發佈的實現:

private static List<String> getClasspathEntriesByPath(String path) throws IOException { 
    InputStream is = Main.class.getClassLoader().getResourceAsStream(path); 

    StringBuilder sb = new StringBuilder(); 
    while (is.available()>0) { 
     byte[] buffer = new byte[1024]; 
     sb.append(new String(buffer, Charset.defaultCharset())); 
    } 

    return Arrays 
      .asList(sb.toString().split("\n"))   // Convert StringBuilder to individual lines 
      .stream()         // Stream the list 
      .filter(line -> line.trim().length()>0)  // Filter out empty lines 
      .collect(Collectors.toList());    // Collect remaining lines into a List again 
} 

雖然我不會期望getResourcesAsStream在目錄上像那樣工作,但確實如此,它運行良好。

+4

您不讀取InputStream – 2017-01-11 13:30:46

0

Spring frameworkPathMatchingResourcePatternResolver這些事是真的真棒:

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的依賴性:

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

這應該工作(如果春天是不是一種選擇):

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

    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; 
}