JAR 파일 내의 파일을 나열하는 방법은 무엇입니까?


114

디렉토리에서 모든 파일을 읽는 코드가 있습니다.

    File textFolder = new File("text_directory");

    File [] texFiles = textFolder.listFiles( new FileFilter() {
           public boolean accept( File file ) {
               return file.getName().endsWith(".txt");
           }
    });

잘 작동합니다. "text_directory"디렉토리에서 ".txt"로 끝나는 모든 파일로 배열을 채 웁니다.

JAR 파일 에서 비슷한 방식으로 디렉토리의 내용을 어떻게 읽을 수 있습니까?

그래서 제가 정말로하고 싶은 것은 내 JAR 파일 내의 모든 이미지를 나열하는 것입니다. 그래서 다음과 같이로드 할 수 있습니다.

ImageIO.read(this.getClass().getResource("CompanyLogo.png"));

( "CompanyLogo"가 "하드 코딩"되어 있기 때문에 작동하지만 JAR 파일 내의 이미지 수는 가변 길이가 10 ~ 200 개일 수 있습니다.)

편집하다

그래서 내 주요 문제는 다음과 같습니다 . 내 메인 클래스 가있는 JAR 파일이름 을 아는 방법 ?

나는 그것을 사용하여 읽을 수 있었다 java.util.Zip.

내 구조는 다음과 같습니다.

그들은 다음과 같습니다.

my.jar!/Main.class
my.jar!/Aux.class
my.jar!/Other.class
my.jar!/images/image01.png
my.jar!/images/image02a.png
my.jar!/images/imwge034.png
my.jar!/images/imagAe01q.png
my.jar!/META-INF/manifest 

지금은 다음을 사용하여 "images / image01.png"인스턴스를로드 할 수 있습니다.

    ImageIO.read(this.getClass().getResource("images/image01.png));

하지만 파일 이름을 알고 있기 때문에 나머지 파일을 동적으로로드해야합니다.


그냥 생각-왜 이미지를 별도의 파일로 압축하고 다른 jar의 클래스에서 항목을 읽어 보지 않겠습니까?
Vineet Reynolds

3
배포 / 설치를 위해 "추가"단계가 필요하기 때문입니다. :( 알다시피, 최종 사용자.
OscarRyz

jar를 만들었으므로 트릭을 시도하는 대신 파일 목록을 포함하는 것이 좋습니다.
Tom Hawtin-tackline

글쎄, 내가 틀렸을 수도 있지만 항아리는 다른 항아리 안에 포함될 수 있습니다. one-jar (TM) 패키징 솔루션 ibm.com/developerworks/java/library/j-onejar 이이를 기반으로 작동합니다. 단, 귀하의 경우 능력 부하 등급이 필요하지 않습니다.
Vineet Reynolds

답변:


91
CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
if (src != null) {
  URL jar = src.getLocation();
  ZipInputStream zip = new ZipInputStream(jar.openStream());
  while(true) {
    ZipEntry e = zip.getNextEntry();
    if (e == null)
      break;
    String name = e.getName();
    if (name.startsWith("path/to/your/dir/")) {
      /* Do something with this entry. */
      ...
    }
  }
} 
else {
  /* Fail... */
}

Java 7에서는 FileSystemJAR (zip) 파일에서을 생성 한 다음 NIO의 디렉토리 검색 및 필터링 메커니즘을 사용하여 검색 할 수 있습니다. 이렇게하면 JAR 및 "폭발 된"디렉토리를 처리하는 코드를 더 쉽게 작성할 수 있습니다.


헤이 감사합니다 ... 몇 시간 동안 이것을 할 방법을 찾고 있습니다 !!
Newtopian

9
예,이 코드는이 jar 파일 내의 모든 항목을 나열하려는 경우 작동합니다. 그러나 jar 내부의 하위 디렉토리 (예 : example.jar / dir1 / dir2 / )를 나열하려면 어떻게이 하위 디렉토리에있는 모든 파일을 직접 나열 할 수 있습니까? 아니면이 jar 파일의 압축을 풀어야합니까? 도와 주셔서 감사합니다!
Ensom Hodder 2012-08-11

언급 된 Java 7 접근 방식은 @ acheron55의 답변에 나열되어 있습니다.
Vadzim 2015-08-03

@Vadzim acheron55의 대답이 Java 7에 대한 것입니까? Java 7에서는 Files.walk () 또는 java.util.Stream을 찾지 못했지만 Java 8에서는 docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html
Bruce 일요일

@BruceSun, Java 7에서는 대신 Files.walkFileTree (...) 를 사용할 수 있습니다 .
Vadzim

80

IDE 및 .jar 파일 모두에서 작동하는 코드 :

import java.io.*;
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.stream.*;

public class ResourceWalker {
    public static void main(String[] args) throws URISyntaxException, IOException {
        URI uri = ResourceWalker.class.getResource("/resources").toURI();
        Path myPath;
        if (uri.getScheme().equals("jar")) {
            FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap());
            myPath = fileSystem.getPath("/resources");
        } else {
            myPath = Paths.get(uri);
        }
        Stream<Path> walk = Files.walk(myPath, 1);
        for (Iterator<Path> it = walk.iterator(); it.hasNext();){
            System.out.println(it.next());
        }
    }
}

5
FileSystems.newFileSystem()소요 Map<String, ?>당신이 지정할 필요가 있으므로, Collections.emptyMap()그것이 적절하게 입력 하나를 반환 할 필요가있다. 이것은 작동합니다 : Collections.<String, Object>emptyMap().
Zero3 2015

6
환상적 !!! 하지만 URI uri = MyClass.class.getResource ( "/ resources"). toURI (); MyClass.class.getClassLoader (). getResource ( "/ resources"). toURI (); 즉, getClassLoader (). 그렇지 않으면 그것은 나를 위해 작동하지 않았습니다.
EMM

8
닫는 것을 잊지 마세요 fileSystem!
gmjonker

3
이것은 1.8에 대한 첫 번째 답변이어야합니다 (의 walk메서드 Files는 1.8에서만 사용 가능). 유일한 문제는 리소스 디렉토리가 Files.walk(myPath, 1)파일뿐만 아니라에 표시된다는 것 입니다. 나는 첫 번째 요소는 단순히 무시 될 수있다 생각
toto_tico

4
myPath = fileSystem.getPath("/resources");나를 위해 작동하지 않습니다. 아무것도 찾지 못합니다. 내 경우에는 "이미지"여야하며 "이미지"디렉토리는 확실히 내 항아리에 포함되어 있습니다!
phip1611

21

erickson의 대답 은 완벽하게 작동했습니다.

다음은 작동 코드입니다.

CodeSource src = MyClass.class.getProtectionDomain().getCodeSource();
List<String> list = new ArrayList<String>();

if( src != null ) {
    URL jar = src.getLocation();
    ZipInputStream zip = new ZipInputStream( jar.openStream());
    ZipEntry ze = null;

    while( ( ze = zip.getNextEntry() ) != null ) {
        String entryName = ze.getName();
        if( entryName.startsWith("images") &&  entryName.endsWith(".png") ) {
            list.add( entryName  );
        }
    }

 }
 webimages = list.toArray( new String[ list.size() ] );

그리고 다음과 같이 내로드 방법을 수정했습니다.

File[] webimages = ... 
BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex].getName() ));

이에:

String  [] webimages = ...

BufferedImage image = ImageIO.read(this.getClass().getResource(webimages[nextIndex]));

9

여러 가지 이유로 매우 안전하지 않은 솔루션이기 때문에 acheron55의 답변 을 확장하고 싶습니다 .

  1. FileSystem개체를 닫지 않습니다 .
  2. FileSystem개체가 이미 존재 하는지 확인하지 않습니다 .
  3. 스레드로부터 안전하지 않습니다.

이것은 다소 안전한 해결책입니다.

private static ConcurrentMap<String, Object> locks = new ConcurrentHashMap<>();

public void walk(String path) throws Exception {

    URI uri = getClass().getResource(path).toURI();
    if ("jar".equals(uri.getScheme()) {
        safeWalkJar(path, uri);
    } else {
        Files.walk(Paths.get(path));
    }
}

private void safeWalkJar(String path, URI uri) throws Exception {

    synchronized (getLock(uri)) {    
        // this'll close the FileSystem object at the end
        try (FileSystem fs = getFileSystem(uri)) {
            Files.walk(fs.getPath(path));
        }
    }
}

private Object getLock(URI uri) {

    String fileName = parseFileName(uri);  
    locks.computeIfAbsent(fileName, s -> new Object());
    return locks.get(fileName);
}

private String parseFileName(URI uri) {

    String schemeSpecificPart = uri.getSchemeSpecificPart();
    return schemeSpecificPart.substring(0, schemeSpecificPart.indexOf("!"));
}

private FileSystem getFileSystem(URI uri) throws IOException {

    try {
        return FileSystems.getFileSystem(uri);
    } catch (FileSystemNotFoundException e) {
        return FileSystems.newFileSystem(uri, Collections.<String, String>emptyMap());
    }
}   

파일 이름을 동기화 할 필요가 없습니다. 매번 동일한 객체에서 동기화 할 수 있습니다 (또는 메서드를 만들 수 있습니다 synchronized). 순전히 최적화입니다.

FileSystem동일한 파일에 대해 인터페이스 를 사용하는 코드에 다른 부분이있을 수 있고 (단일 스레드 응용 프로그램에서도) 간섭을 일으킬 수 있기 때문에 이것이 여전히 문제가되는 해결책이라고 말하고 싶습니다 .
또한 nulls를 확인하지 않습니다 (예 : on getClass().getResource().

이 특정 Java NIO 인터페이스는 스레드로부터 안전하지 않은 전역 / 싱글 톤 리소스를 도입하고 문서가 매우 모호합니다 (제공 업체별 구현으로 인해 많은 알 수 없음). 결과는 다른 FileSystem공급자 (JAR 아님)에 따라 다를 수 있습니다 . 아마 그럴만 한 이유가있을 것입니다. 모르겠습니다. 구현을 조사하지 않았습니다.


1
FS와 같은 외부 리소스의 동기화는 하나의 VM 내에서 그다지 의미가 없습니다. VM 외부에서 액세스하는 다른 애플리케이션이있을 수 있습니다. 자신의 응용 프로그램 내부에서도 파일 이름을 기반으로 한 잠금을 쉽게 우회 할 수 있습니다. 이를 통해 파일 잠금과 같은 OS 동기화 메커니즘에 의존하는 것이 좋습니다.
Espinosa

@Espinosa 파일 이름 잠금 메커니즘은 완전히 우회 할 수 있습니다. 내 대답은 충분히 안전하지 않지만 최소한의 노력으로 Java NIO로 얻을 수있는 최대라고 생각합니다. OS에 의존하여 잠금을 관리하거나 어떤 응용 프로그램이 어떤 파일에 액세스하는지 제어하지 않는 것은 사용자 기반 앱 (예 : 텍스트 편집기)을 빌드하지 않는 한 나쁜 습관입니다. 잠금을 직접 관리하지 않으면 예외가 발생하거나 스레드가 응용 프로그램을 차단하게됩니다. 둘 다 피해야합니다.
Eyal Roth

8

그래서 내 주된 문제는 내 메인 클래스가 사는 항아리의 이름을 아는 방법입니다.

프로젝트가 Jar에 압축되어 있다고 가정하면 (반드시 사실은 아닙니다!), ClassLoader.getResource () 또는 findResource ()를 클래스 이름 (.class가 뒤 따름)과 함께 사용하여 지정된 클래스가 포함 된 jar를 가져올 수 있습니다. 반환되는 URL에서 jar 이름을 구문 분석해야합니다 (그다지 어렵지 않음). 독자를위한 연습으로 남겨 둘 것입니다. :-)

클래스가 항아리의 일부가 아닌 경우를 테스트해야합니다.


1
허-이것이 코멘트없이 다운 모드 화되었을 것이라는 점이 흥미 롭습니다 ... 우리는 항상 위의 기술을 사용하고 잘 작동합니다.
Kevin Day

오래된 문제이지만 나에게 이것은 훌륭한 해킹처럼 보입니다. 0으로 다시 Upvoted :)
Tuukka Mustonen

이 솔루션은 클래스에 CodeSource.
분석 재개 모니카 2,331,977

7

Java 7에 대한 acheron55의 답변 을 포팅 하고 FileSystem객체를 닫았습니다 . 이 코드는 IDE, jar 파일 및 Tomcat 7과의 전쟁 내의 jar에서 작동합니다. 그러나 JBoss 7과의 전쟁에서 항아리에서 작동 하지 않습니다 ( 이 게시물FileSystemNotFoundException: Provider "vfs" not installed 도 참조하십시오 ). 또한 원본 코드와 마찬가지로 errr이 제안한 것처럼 스레드로부터 안전하지 않습니다 . 이러한 이유로 저는이 솔루션을 포기했습니다. 그러나 이러한 문제를 받아 들일 수 있다면 기성 코드는 다음과 같습니다.

import java.io.IOException;
import java.net.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Collections;

public class ResourceWalker {

    public static void main(String[] args) throws URISyntaxException, IOException {
        URI uri = ResourceWalker.class.getResource("/resources").toURI();
        System.out.println("Starting from: " + uri);
        try (FileSystem fileSystem = (uri.getScheme().equals("jar") ? FileSystems.newFileSystem(uri, Collections.<String, Object>emptyMap()) : null)) {
            Path myPath = Paths.get(uri);
            Files.walkFileTree(myPath, new SimpleFileVisitor<Path>() { 
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    System.out.println(file);
                    return FileVisitResult.CONTINUE;
                }
            });
        }
    }
}

5

다음은 "패키지에서 모든 JUnits 실행"을 위해 작성한 방법입니다. 필요에 맞게 조정할 수 있어야합니다.

private static void findClassesInJar(List<String> classFiles, String path) throws IOException {
    final String[] parts = path.split("\\Q.jar\\\\E");
    if (parts.length == 2) {
        String jarFilename = parts[0] + ".jar";
        String relativePath = parts[1].replace(File.separatorChar, '/');
        JarFile jarFile = new JarFile(jarFilename);
        final Enumeration<JarEntry> entries = jarFile.entries();
        while (entries.hasMoreElements()) {
            final JarEntry entry = entries.nextElement();
            final String entryName = entry.getName();
            if (entryName.startsWith(relativePath)) {
                classFiles.add(entryName.replace('/', File.separatorChar));
            }
        }
    }
}

편집 : 아,이 경우이 스 니펫도 필요할 수 있습니다 (동일한 사용 사례 :))

private static File findClassesDir(Class<?> clazz) {
    try {
        String path = clazz.getProtectionDomain().getCodeSource().getLocation().getFile();
        final String codeSourcePath = URLDecoder.decode(path, "UTF-8");
        final String thisClassPath = new File(codeSourcePath, clazz.getPackage().getName().repalce('.', File.separatorChar));
    } catch (UnsupportedEncodingException e) {
        throw new AssertionError("impossible", e);
    }
}

1
큰 문제는 처음에 jar 파일 이름을 아는 것입니다. Main-Class :가 사는 항아리입니다.
OscarRyz

5

다음은 Reflections 라이브러리를 사용하여 리소스 콘텐츠를 가져 오기 위해 몇 가지 Guava 특전으로 강화 된 정규식 이름 패턴으로 클래스 경로를 재귀 적으로 스캔 하는 예입니다 .

Reflections reflections = new Reflections("com.example.package", new ResourcesScanner());
Set<String> paths = reflections.getResources(Pattern.compile(".*\\.template$"));

Map<String, String> templates = new LinkedHashMap<>();
for (String path : paths) {
    log.info("Found " + path);
    String templateName = Files.getNameWithoutExtension(path);
    URL resource = getClass().getClassLoader().getResource(path);
    String text = Resources.toString(resource, StandardCharsets.UTF_8);
    templates.put(templateName, text);
}

이것은 항아리와 폭발 클래스 모두에서 작동합니다.


리플렉션은 여전히 ​​Java 9 이상을 지원하지 않습니다 : github.com/ronmamo/reflections/issues/186 . 경쟁 도서관에 대한 링크가 있습니다.
Vadzim

3

jar 파일은 구조화 된 매니페스트가있는 zip 파일입니다. 일반적인 자바 zip 도구를 사용하여 jar 파일을 열고 그런 방식으로 파일 내용을 스캔하고 스트림을 확장 할 수 있습니다. 그런 다음 getResourceAsStream 호출에서이를 사용하면 모든 것이 엉망이됩니다.

수정 / 설명 후

모든 비트와 조각을 기억하는 데 1 분이 걸렸고이를 수행 할 수있는 더 깨끗한 방법이 있다고 확신합니다.하지만 제가 미쳤다는 것을 알고 싶었습니다. 내 프로젝트에서 image.jpg는 기본 jar 파일의 일부에있는 파일입니다. 메인 클래스 (SomeClass가 진입 점)의 클래스 로더를 가져 와서 image.jpg 리소스를 검색하는 데 사용합니다. 그런 다음이 ImageInputStream 사물에 들어가는 스트림 마술과 모든 것이 좋습니다.

InputStream inputStream = SomeClass.class.getClassLoader().getResourceAsStream("image.jpg");
JPEGImageReaderSpi imageReaderSpi = new JPEGImageReaderSpi();
ImageReader ir = imageReaderSpi.createReaderInstance();
ImageInputStream iis = new MemoryCacheImageInputStream(inputStream);
ir.setInput(iis);
....
ir.read(0); //will hand us a buffered image

이 jar에는 기본 프로그램과 리소스가 포함되어 있습니다. 셀프 항아리를 어떻게 참조합니까? jar 파일 내에서?
OscarRyz

JAR 파일을 참조하려면 "blah.JAR"를 문자열로 사용하십시오. new File("blah.JAR")예를 들어를 사용하여 JAR을 나타내는 File 객체를 만들 수 있습니다 . "blah.JAR"를 JAR 이름으로 바꾸십시오.
Thomas Owens

이미 부족한 병과 같은 병이라면 클래스 로더가 병 안의 내용을 볼 수 있어야합니다. 처음에 무엇을하려고했는지 오해했습니다.
Mikeb

2
예, 이미 가지고 있습니다. 문제는 "... getResourceAsStream ("*. jpg "); ..."즉, 포함 된 파일을 동적으로 나열합니다.
OscarRyz

3

실제 JAR 파일이 주어지면 JarFile.entries(). 하지만 JAR 파일의 위치를 ​​알아야합니다. 클래스 로더에게 얻을 수있는 모든 것을 나열하도록 요청할 수는 없습니다.

에서 반환 된 URL을 기반으로 JAR 파일의 위치를 ​​알아낼 수 있어야 ThisClassName.class.getResource("ThisClassName.class")하지만 약간 까다로울 수 있습니다.


귀하의 답변을 읽고 또 다른 질문이 제기되었습니다. 호출 결과 : this.getClass (). getResource ( "/ my_directory"); .... 디렉토리로 사용될 수있는 URL을 반환해야합니다. 아니 ... 한번해볼 게요.
OscarRyz

항상 JAR의 위치를 ​​알고 있습니다. "."에 있습니다. JAR의 이름이 무언가로 알려진 한 어딘가에 String 상수를 사용할 수 있습니다. 자, 사람들이 JAR의 이름을 바꾸면 ...
Thomas Owens

@Thomas : 현재 디렉터리에서 앱을 실행하고 있다고 가정합니다. "java -jar foo / bar / baz.jar"의 문제점은 무엇입니까?
Jon Skeet

나는 Jar에 코드가 있다면 new File("baz.jar)File 객체가 JAR 파일을 나타낼 것이라고 믿습니다 (확인해야합니다) .
Thomas Owens

@Thomas : 나는 그렇게 믿지 않는다. 나는 그것이 프로세스의 현재 작업 디렉토리와 관련이 있다고 생각합니다. 그래도 확인해야합니다 :)
Jon Skeet

3

얼마 전에 JAR 내부에서 클래스를 가져 오는 함수를 만들었습니다.

public static Class[] getClasses(String packageName) 
throws ClassNotFoundException{
    ArrayList<Class> classes = new ArrayList<Class> ();

    packageName = packageName.replaceAll("\\." , "/");
    File f = new File(jarName);
    if(f.exists()){
        try{
            JarInputStream jarFile = new JarInputStream(
                    new FileInputStream (jarName));
            JarEntry jarEntry;

            while(true) {
                jarEntry=jarFile.getNextJarEntry ();
                if(jarEntry == null){
                    break;
                }
                if((jarEntry.getName ().startsWith (packageName)) &&
                        (jarEntry.getName ().endsWith (".class")) ) {
                    classes.add(Class.forName(jarEntry.getName().
                            replaceAll("/", "\\.").
                            substring(0, jarEntry.getName().length() - 6)));
                }
            }
        }
        catch( Exception e){
            e.printStackTrace ();
        }
        Class[] classesA = new Class[classes.size()];
        classes.toArray(classesA);
        return classesA;
    }else
        return null;
}

2
public static ArrayList<String> listItems(String path) throws Exception{
    InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(path);
    byte[] b = new byte[in.available()];
    in.read(b);
    String data = new String(b);
    String[] s = data.split("\n");
    List<String> a = Arrays.asList(s);
    ArrayList<String> m = new ArrayList<>(a);
    return m;
}

3
이 코드 스 니펫은 문제를 해결할 수 있지만 질문에 대한 이유 또는 답을 설명하지 않습니다. 게시물의 품질을 향상시키는 데 도움이되는 코드에 대한 설명을 포함 해주세요 . 앞으로 독자를위한 질문에 답하고 있으며, 해당 사용자는 코드 제안 이유를 모를 수 있습니다.
사무엘 필립

jar 파일에서 코드를 실행할 때 데이터가 비어 있습니다.
Aguid


1

클래스 경로의 모든 리소스를 나열하는 가장 강력한 메커니즘은 현재이 패턴을 ClassGraph와 함께 사용하는 것입니다 . 새로운 JPMS 모듈 시스템을 포함하여 가능한 가장 광범위한 클래스 경로 사양 메커니즘을 처리하기 때문 입니다. (저는 ClassGraph의 저자입니다.)

내 메인 클래스가있는 JAR 파일의 이름을 아는 방법은 무엇입니까?

URI mainClasspathElementURI;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("x.y.z")
        .enableClassInfo().scan()) {
    mainClasspathElementURI =
            scanResult.getClassInfo("x.y.z.MainClass").getClasspathElementURI();
}

JAR 파일 내에서 비슷한 방식으로 디렉토리의 내용을 어떻게 읽을 수 있습니까?

List<String> classpathElementResourcePaths;
try (ScanResult scanResult = new ClassGraph().overrideClasspath(mainClasspathElementURI)
        .scan()) {
    classpathElementResourcePaths = scanResult.getAllResources().getPaths();
}

자원을 다루는 다른 방법많이 있습니다.


1
내 Scala 프로젝트에서 쉽게 사용할 수있는 아주 멋진 패키지입니다. 감사합니다.
zslim

0

jar URL에서 파일을 나열 / 읽는 다른 방법이며 중첩 된 jar에 대해 반복적으로 수행합니다.

https://gist.github.com/trung/2cd90faab7f75b3bcbaa

URL urlResource = Thead.currentThread().getContextClassLoader().getResource("foo");
JarReader.read(urlResource, new InputStreamCallback() {
    @Override
    public void onFile(String name, InputStream is) throws IOException {
        // got file name and content stream 
    }
});

0

도로를위한 또 하나 :

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;

import static java.nio.file.FileSystems.newFileSystem;
import static java.util.Collections.emptyMap;

public class ResourceWalker {
  private static final PathMatcher FILE_MATCHER =
      FileSystems.getDefault().getPathMatcher( "glob:**.ttf" );

  public static List<Path> walk( final String directory )
      throws URISyntaxException, IOException {
    final List<Path> filenames = new ArrayList<>();
    final var resource = ResourceWalker.class.getResource( directory );

    if( resource != null ) {
      final var uri = resource.toURI();
      final var path = uri.getScheme().equals( "jar" )
          ? newFileSystem( uri, emptyMap() ).getPath( directory )
          : Paths.get( uri );
      final var walk = Files.walk( path, 10 );

      for( final var it = walk.iterator(); it.hasNext(); ) {
        final Path p = it.next();
        if( FILE_MATCHER.matches( p ) ) {
          filenames.add( p );
        }
      }
    }

    return filenames;
  }
}

와일드 카드 글 로빙을 사용하기 때문에 특정 파일 이름을 일치시키는 데 좀 더 유연합니다.


보다 기능적인 스타일 :

import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.util.function.Consumer;

import static java.nio.file.FileSystems.newFileSystem;
import static java.util.Collections.emptyMap;

/**
 * Responsible for finding file resources.
 */
public class ResourceWalker {
  private static final PathMatcher FILE_MATCHER =
      FileSystems.getDefault().getPathMatcher( "glob:**.ttf" );

  public static void walk( final String dirName, final Consumer<Path> f )
      throws URISyntaxException, IOException {
    final var resource = ResourceWalker.class.getResource( dirName );

    if( resource != null ) {
      final var uri = resource.toURI();
      final var path = uri.getScheme().equals( "jar" )
          ? newFileSystem( uri, emptyMap() ).getPath( dirName )
          : Paths.get( uri );
      final var walk = Files.walk( path, 10 );

      for( final var it = walk.iterator(); it.hasNext(); ) {
        final Path p = it.next();
        if( FILE_MATCHER.matches( p ) ) {
          f.accept( p );
        }
      }
    }
  }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.