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 

अभी मैं "चित्र / image01.png" उदाहरण के लिए लोड करने में सक्षम हूं:

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

लेकिन केवल इसलिए कि मुझे फ़ाइल का नाम पता है, बाकी के लिए मुझे उन्हें गतिशील रूप से लोड करना होगा।


बस एक विचार - क्यों नहीं एक अलग फ़ाइल में ज़िप / जार छवियों और एक और जार में अपनी कक्षा से इसमें प्रविष्टियों को पढ़ने के लिए?
विनीत रेनॉल्ड्स

3
क्योंकि इसे वितरण / स्थापना के लिए "अतिरिक्त" कदम की आवश्यकता होगी। :( आप जानते हैं, अंतिम उपयोगकर्ता।
ऑस्कररेज़

यह देखते हुए कि आपने जार बनाया है, आप किसी भी ट्रिक को आज़माने के बजाय इसके भीतर फाइलों की सूची को शामिल कर सकते हैं।
टॉम हैटिन -

ठीक है, मुझसे गलती हो सकती है लेकिन जार को अन्य जार के अंदर रखा जा सकता है। वन-जार (TM) पैकेजिंग समाधान ibm.com/developerworks/java/library/j-onejar इस आधार पर काम करता है। सिवाय, आपके मामले में आपको क्षमता भार वर्गों की आवश्यकता नहीं है।
विनीत रेनॉल्ड्स

जवाबों:


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... */
}

ध्यान दें कि जावा 7 में, आप FileSystemJAR (ज़िप) फ़ाइल से बना सकते हैं , और फिर इसके माध्यम से खोज करने के लिए NIO की निर्देशिका चलने और फ़िल्टरिंग तंत्र का उपयोग कर सकते हैं। इससे कोड लिखना आसान हो जाएगा जो JAR और "विस्फोट" निर्देशिकाओं को संभालता है।


हे धन्यवाद ... अब कुछ घंटों के लिए ऐसा करने के लिए एक रास्ता तलाश रहा था !!
न्यूटोपियन

9
हां यह कोड काम करता है अगर हम इस जार फ़ाइल के अंदर सभी प्रविष्टियों को सूचीबद्ध करना चाहते हैं। लेकिन अगर मैं सिर्फ जार के अंदर एक उपनिर्देशिका को सूचीबद्ध करना चाहता हूं, उदाहरण के लिए, example.jar / dir1 / dir2 / , मैं इस उपनिर्देशिका के अंदर सभी फ़ाइलों को सीधे कैसे सूचीबद्ध कर सकता हूं? या मुझे इस जार फ़ाइल को अनज़िप करने की आवश्यकता है? मैं आपकी मदद की बहुत सराहना करता हूं!
२२:

उल्लेखित जावा 7 दृष्टिकोण @ acheron55 के उत्तर में सूचीबद्ध है ।
वडज़िम

@Vadzim क्या आपको यकीन है कि acheron55 का जवाब Java 7 के लिए है? मुझे Java 7 में Files.walk () या java.util.Stream नहीं मिला, लेकिन जावा 8 में: docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html
ब्रूस सूर्य

@BruceSun, java 7 में आप इसके बजाय Files.walkFileTree (...) का उपयोग कर सकते हैं ।
वडज़िम

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():।
जीरो 3

6
बहुत खुबस!!! लेकिन URI uri = MyClass.class.getResource ("/ resource") .URI (); MyClass.class.getClassLoader () होना चाहिए। getResource ("/ resource"), 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

एरिकसन के जवाब ने पूरी तरह से काम किया:

यहां काम करने का कोड है।

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 (उदाहरण के लिए,) के लिए जाँच नहीं करता है getClass().getResource()

यह विशेष रूप से जावा एनआईओ इंटरफ़ेस एक प्रकार का भयानक है, क्योंकि यह एक वैश्विक / एकल गैर-थ्रेड-सुरक्षित संसाधन का परिचय देता है, और इसका प्रलेखन अत्यंत अस्पष्ट (प्रदाता विशिष्ट कार्यान्वयन के कारण बहुत सारे अज्ञात) है। परिणाम अन्य FileSystemप्रदाताओं (JAR नहीं) के लिए भिन्न हो सकते हैं । शायद इस तरह से होने का एक अच्छा कारण है; मुझे नहीं पता, मैंने कार्यान्वयन पर शोध नहीं किया है।


1
एफएस जैसे बाहरी संसाधनों का सिंक्रोनाइज़ेशन, एक वीएम के भीतर बहुत अधिक समझ में नहीं आता है। आपके VM के बाहर इसे एक्सेस करने वाले अन्य एप्लिकेशन हो सकते हैं। अपने स्वयं के अनुप्रयोग के अंदर भी, फ़ाइल नाम के आधार पर आपके लॉकिंग को आसानी से बायपास किया जा सकता है। इस चीजों के साथ ओएस सिंक्रनाइज़ेशन तंत्र पर भरोसा करना बेहतर है, जैसे फ़ाइल लॉकिंग।
एस्पिनोसा

@Espinosa फ़ाइल-नाम लॉक तंत्र पूरी तरह से बायपास हो सकता है; मेरा उत्तर पर्याप्त रूप से सुरक्षित नहीं है, लेकिन मेरा मानना ​​है कि यह सबसे कम आप जावा एनआईओ के न्यूनतम प्रयास के साथ प्राप्त कर सकते हैं। एक टेक्स्ट एडिटर का कहना है कि जब तक आप एक कॉस्ट्यूमेर-आधारित ऐप का निर्माण नहीं करते हैं, तब तक लॉक को प्रबंधित करने के लिए ओएस पर भरोसा करना, या उन एप्लिकेशन का एक्सेस न होना, जो फाइलों तक पहुंचना एक बुरा अभ्यास IMHO है। अपने दम पर ताले का प्रबंधन नहीं करने पर या तो अपवादों को फेंक दिया जाएगा, या धागे को आवेदन को अवरुद्ध करने का कारण होगा - दोनों से बचा जाना चाहिए।
इयाल रोथ

8

इसलिए मुझे लगता है कि मेरी मुख्य समस्या यह होगी कि जार का नाम कैसे पता चलेगा, जहां मेरा मुख्य वर्ग रहता है।

यह मानते हुए कि आपका प्रोजेक्ट जार में पैक किया गया है (आवश्यक रूप से सच नहीं है!), आप दिए गए वर्ग को शामिल करने के लिए जार पाने के लिए वर्ग नाम (.class) के साथ ClassLoader.getResource () या findResource () का उपयोग कर सकते हैं। आपको URL से उस जार नाम को पार्स करना होगा जो लौटाया जाता है (वह कठिन नहीं), जिसे मैं पाठक के लिए एक अभ्यास के रूप में छोड़ दूंगा :-)

उस मामले के लिए परीक्षण करना सुनिश्चित करें जहां कक्षा एक जार का हिस्सा नहीं है।


1
हुह - दिलचस्प है कि यह नीचे टिप्पणी के बिना moded होता ... हम हर समय उपरोक्त तकनीक का उपयोग करते हैं और यह ठीक काम करता है।
केविन डे

एक पुराना मुद्दा है, लेकिन मेरे लिए यह ठीक हैक की तरह लगता है। शून्य करने के लिए :) वापस upvoted
Tuukka मुस्टोनेन

अपवोट किया गया, क्योंकि यह एकमात्र समाधान है जिसे इस मामले के लिए सूचीबद्ध किया गया है जब एक वर्ग नहीं है CodeSource
मोनिका 2331977

7

मैंने acheron55 के उत्तर को Java 7 में पोर्ट कर लिया है और FileSystemऑब्जेक्ट को बंद कर दिया है । यह कोड आईडीई के, जार फाइलों में और टॉमकैट 7 पर एक युद्ध के अंदर जार में काम करता है; लेकिन ध्यान दें कि यह JBoss 7 पर युद्ध के अंदर एक जार में काम नहीं करता है (यह देता है FileSystemNotFoundException: Provider "vfs" not installed, यह पोस्ट भी देखें )। इसके अलावा, मूल कोड की तरह, यह थ्रेड सुरक्षित नहीं है, जैसा कि इर्र द्वारा सुझाया गया है । इन कारणों से मैंने इस समाधान को छोड़ दिया है; हालाँकि, यदि आप इन मुद्दों को स्वीकार कर सकते हैं, तो यहां मेरा तैयार कोड है:

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
मुझे लगता है कि बड़ी समस्या यह है कि जार फ़ाइल नाम को पहले स्थान पर जाना जाए। यह जार है जहां मेन-क्लास: रहता है।
OscarRyz

5

यहाँ संसाधन पुलों को प्राप्त करने के लिए अमरूद के एक जोड़े के साथ संवर्धित नाम पैटर्न regex द्वारा क्लासपैथ को स्कैन करने के लिए रिफ्लेक्शंस लाइब्रेरी का उपयोग करने का एक उदाहरण है :

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

यह जार और विस्फोट दोनों वर्गों के साथ काम करता है।


सावधान रहें कि प्रतिबिंब अभी भी जावा 9 और उससे अधिक का समर्थन नहीं करते हैं: github.com/ronmamo/reflections/issues/186 । वहाँ प्रतिस्पर्धी पुस्तकालयों के लिए लिंक हैं।
वडज़िम

3

एक जार फ़ाइल एक संरचित प्रकट के साथ एक ज़िप फ़ाइल है। आप सामान्य जावा जिप टूल्स के साथ जार फाइल को खोल सकते हैं और फाइल कंटेंट को उस तरह से स्कैन कर सकते हैं, जैसे कि स्ट्रीम, इनफ्लो स्ट्रीम इत्यादि। फिर एक getResourceAsStream कॉल में इसका उपयोग कर सकते हैं, और यह सभी hunky dory होनी चाहिए।

EDIT / स्पष्टीकरण के बाद

मुझे सभी बिट्स और टुकड़ों को याद करने में एक मिनट लगा और मुझे यकीन है कि इसे करने के लिए क्लीनर तरीके हैं, लेकिन मैं यह देखना चाहता था कि मैं पागल नहीं था। मेरी परियोजना में image.jpg मुख्य जार फ़ाइल के कुछ हिस्से में एक फ़ाइल है। मुझे मुख्य वर्ग का क्लास लोडर मिलता है (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

इस जार में मुख्य कार्यक्रम और संसाधन होते हैं। मैं आत्म जार का उल्लेख कैसे करूँ? जार फ़ाइल के भीतर से?
OscarRyz

JAR फ़ाइल को संदर्भित करने के लिए, स्ट्रिंग के रूप में बस "blah.JAR" का उपयोग करें। आप new File("blah.JAR")उदाहरण के लिए, JAR का प्रतिनिधित्व करने वाली फ़ाइल ऑब्जेक्ट बनाने के लिए उपयोग कर सकते हैं । बस अपने JAR के नाम के साथ "blah.JAR" बदलें।
थॉमस ओवेन्स

यदि इसका वही जार जिसे आप पहले से चला रहे हैं, तो क्लास लोडर को जार के अंदर सामान देखने में सक्षम होना चाहिए ... मुझे गलतफहमी हुई कि आप शुरू में क्या करना चाह रहे थे।
मिकब

2
ठीक है, मेरे पास पहले से ही है, समस्या यह है कि जब मुझे कुछ चाहिए: "... getResourceAsStream (" *। Jpg ") ... ...", गतिशील रूप से, सम्‍मिलित फ़ाइलों को सूचीबद्ध करें।
ऑस्करराइज

3

एक वास्तविक JAR फ़ाइल को देखते हुए, आप उपयोग की जाने वाली सामग्री को सूचीबद्ध कर सकते हैं JarFile.entries()। हालांकि आपको JAR फ़ाइल का स्थान जानना होगा - आप क्लासलोडर को यह सब कुछ सूचीबद्ध करने के लिए नहीं कह सकते हैं जो इसे प्राप्त कर सकता है।

आप जिस URL से लौटे हैं ThisClassName.class.getResource("ThisClassName.class"), उसके आधार पर JAR फ़ाइल के स्थान का पता लगाने में सक्षम होना चाहिए , लेकिन यह बहुत कम हो सकता है।


आपके जवाब को पढ़कर एक और सवाल उठा। कॉल करने से क्या होगा: this.getClass ()। GetResource ("/ my_directory"); यह एक ऐसा URL लौटाए जो बदले में .... निर्देशिका के रूप में उपयोग किया जा सके? नहीं ... मुझे इसे आज़माने दो।
OscarRyz

आप हमेशा JAR के स्थान को जानते हैं - यह "" में है। जब तक JAR का नाम कुछ जाना जाता है, तब तक आप कहीं न कहीं एक स्ट्रिंग स्थिरांक का उपयोग कर सकते हैं। अब, अगर लोग JAR का नाम बदलते हैं ...
थॉमस ओवंस

@ थोमस: यह मानकर कि आप वर्तमान निर्देशिका से ऐप चला रहे हैं। "Java -jar foo / bar / baz.jar" में क्या गलत है?
जॉन स्कीट

मुझे विश्वास है (और सत्यापित करना होगा), कि यदि आपके पास अपने जार में कोड था new File("baz.jar), तो फ़ाइल ऑब्जेक्ट आपकी JAR फ़ाइल का प्रतिनिधित्व करेगा।
थॉमस ओवेन्स

@ थोमस: मेरा ऐसा मानना ​​नहीं है। मेरा मानना ​​है कि यह प्रक्रिया की वर्तमान कार्यशील निर्देशिका के सापेक्ष होगा। मुझे बहुत जाँच करनी होगी :)
जॉन स्कीट

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
हालांकि यह कोड स्निपेट समस्या को हल कर सकता है, यह इस बात की व्याख्या नहीं करता है कि यह प्रश्न का उत्तर क्यों या कैसे देता है। कृपया अपने कोड के लिए एक स्पष्टीकरण शामिल करें , क्योंकि यह वास्तव में आपके पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है।
शमूएल

जब हम जार फ़ाइल से कोड निष्पादित करते हैं तो डेटा खाली होता है।
अगुिड


1

क्लासपाथ में सभी संसाधनों को सूचीबद्ध करने के लिए सबसे मजबूत तंत्र वर्तमान में क्लासग्राफ के साथ इस पैटर्न का उपयोग करना है , क्योंकि यह नए जेपीएमएस मॉड्यूल सिस्टम सहित क्लासपैथ विनिर्देशन तंत्र के व्यापक संभव सरणी को संभालता है। (मैं क्लासग्राफ का लेखक हूं।)

जहां मेरा मुख्य वर्ग रहता है, वहां 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
मेरी स्काला परियोजना में बहुत अच्छा पैकेज, आसानी से प्रयोग करने योग्य, धन्यवाद।
zslim

0

जार URL से फ़ाइलों को सूचीबद्ध करने / पढ़ने का बस एक अलग तरीका है और यह नेस्टेड जार के लिए पुनरावृत्ति करता है

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 );
        }
      }
    }
  }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.