Domanda

Sto provando ad accedere a un file XML all'interno di un file jar, da un vaso separato in esecuzione come applicazione desktop. Posso ottenere l'URL del file di cui ho bisogno, ma quando lo passo a un FileReader (come stringa) ottengo un FileNotFoundException che dice " Il nome del file, il nome della directory o la sintassi dell'etichetta del volume non è corretto. & Quot;

Come punto di riferimento, non ho problemi a leggere le risorse di immagine dallo stesso vaso, passando l'URL a un costruttore di ImageIcon. Questo sembra indicare che il metodo che sto usando per ottenere l'URL è corretto.

URL url = getClass().getResource("/xxx/xxx/xxx/services.xml");
ServicesLoader jsl = new ServicesLoader( url.toString() );

All'interno della classe ServicesLoader che ho

XMLReader xr = XMLReaderFactory.createXMLReader();
xr.setContentHandler( this );
xr.setErrorHandler( this );
xr.parse( new InputSource( new FileReader( filename )));

Cosa c'è di sbagliato nell'usare questa tecnica per leggere il file XML?

È stato utile?

Soluzione 4

Il problema era che stavo andando troppo oltre nel chiamare il metodo di analisi di XMLReader. Il metodo parse accetta un InputSource, quindi non c'era motivo di usare nemmeno un FileReader. Modifica l'ultima riga del codice sopra in

xr.parse( new InputSource( filename ));

funziona perfettamente.

Altri suggerimenti

Sembra che tu voglia usare java.lang.Class.getResourceAsStream (String) , vedi

http : //java.sun.com/javase/6/docs/api/java/lang/Class.html#getResourceAsStream (java.lang.String)

Non dici se si tratta di un'app desktop o web. Vorrei utilizzare il metodo getResourceAsStream () da un ClassLoader appropriato se si tratta di un desktop o del contesto se si tratta di un'app Web.

Sembra che tu stia usando il risultato URL.toString come argomento per il costruttore FileReader . URL.toString è un po 'rotto, e invece dovresti generalmente usare url.toURI (). toString () . In ogni caso, la stringa non è un percorso di file.

Invece, dovresti:

  • Passa URL a ServicesLoader e lascia che chiami openStream o simile.
  • Usa Class.getResourceAsStream e passa semplicemente il flusso, possibilmente all'interno di un InputSource . (Ricorda di verificare la presenza di null poiché l'API è un po 'disordinata.)

Vorrei sottolineare che un problema è che cosa succede se le stesse risorse si trovano in più file jar. Diciamo che vuoi leggere /org/node/foo.txt, ma non da un file, ma da ogni file jar.

Ho riscontrato questo stesso problema diverse volte prima. Speravo in JDK 7 che qualcuno avrebbe scritto un filesystem classpath, ma purtroppo non ancora.

Spring ha la classe di risorse che consente di caricare abbastanza bene le risorse del percorso di classe.

Ho scritto un piccolo prototipo per risolvere questo problema di lettura delle risorse da più file jar. Il prototipo non gestisce tutti i casi limite, ma cerca le risorse nelle directory che si trovano nei file jar.

Ho usato Stack Overflow per un po 'di tempo. Questa è la seconda risposta che ricordo di aver risposto a una domanda, quindi perdonami se vado troppo a lungo (è la mia natura).

Questo è un lettore di risorse prototipo. Il prototipo è privo di solidi controlli degli errori.

Ho due file jar prototipo che ho installato.

 <pre>
         <dependency>
              <groupId>invoke</groupId>
              <artifactId>invoke</artifactId>
              <version>1.0-SNAPSHOT</version>
          </dependency>

          <dependency>
               <groupId>node</groupId>
               <artifactId>node</artifactId>
               <version>1.0-SNAPSHOT</version>
          </dependency>

I file jar hanno ciascuno un file in / org / node / chiamato resource.txt.

Questo è solo un prototipo di come sarebbe un gestore con classpath: // Ho anche un resource.foo.txt nelle mie risorse locali per questo progetto.

Li raccoglie tutti e li stampa.

   

    package com.foo;

    import java.io.File;
    import java.io.FileReader;
    import java.io.InputStreamReader;
    import java.io.Reader;
    import java.net.URI;
    import java.net.URL;
    import java.util.Enumeration;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipFile;

    /**
    * Prototype resource reader.
    * This prototype is devoid of error checking.
    *
    *
    * I have two prototype jar files that I have setup.
    * <pre>
    *             <dependency>
    *                  <groupId>invoke</groupId>
    *                  <artifactId>invoke</artifactId>
    *                  <version>1.0-SNAPSHOT</version>
    *              </dependency>
    *
    *              <dependency>
    *                   <groupId>node</groupId>
    *                   <artifactId>node</artifactId>
    *                   <version>1.0-SNAPSHOT</version>
    *              </dependency>
    * </pre>
    * The jar files each have a file under /org/node/ called resource.txt.
    * <br />
    * This is just a prototype of what a handler would look like with classpath://
    * I also have a resource.foo.txt in my local resources for this project.
    * <br />
    */
    public class ClasspathReader {

        public static void main(String[] args) throws Exception {

            /* This project includes two jar files that each have a resource located
               in /org/node/ called resource.txt.
             */


            /* 
              Name space is just a device I am using to see if a file in a dir
              starts with a name space. Think of namespace like a file extension 
              but it is the start of the file not the end.
            */
            String namespace = "resource";

            //someResource is classpath.
            String someResource = args.length > 0 ? args[0] :
                    //"classpath:///org/node/resource.txt";   It works with files
                    "classpath:///org/node/";                 //It also works with directories

            URI someResourceURI = URI.create(someResource);

            System.out.println("URI of resource = " + someResourceURI);

            someResource = someResourceURI.getPath();

            System.out.println("PATH of resource =" + someResource);

            boolean isDir = !someResource.endsWith(".txt");


            /** Classpath resource can never really start with a starting slash.
             * Logically they do, but in reality you have to strip it.
             * This is a known behavior of classpath resources.
             * It works with a slash unless the resource is in a jar file.
             * Bottom line, by stripping it, it always works.
             */
            if (someResource.startsWith("/")) {
                someResource = someResource.substring(1);
            }

              /* Use the ClassLoader to lookup all resources that have this name.
                 Look for all resources that match the location we are looking for. */
            Enumeration resources = null;

            /* Check the context classloader first. Always use this if available. */
            try {
                resources = 
                    Thread.currentThread().getContextClassLoader().getResources(someResource);
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            if (resources == null || !resources.hasMoreElements()) {
                resources = ClasspathReader.class.getClassLoader().getResources(someResource);
            }

            //Now iterate over the URLs of the resources from the classpath
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();


                /* if the resource is a file, it just means that we can use normal mechanism
                    to scan the directory.
                */
                if (resource.getProtocol().equals("file")) {
                    //if it is a file then we can handle it the normal way.
                    handleFile(resource, namespace);
                    continue;
                }

                System.out.println("Resource " + resource);

               /*

                 Split up the string that looks like this:
                 jar:file:/Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar!/org/node/
                 into
                    this /Users/rick/.m2/repository/invoke/invoke/1.0-SNAPSHOT/invoke-1.0-SNAPSHOT.jar
                 and this
                     /org/node/
                */
                String[] split = resource.toString().split(":");
                String[] split2 = split[2].split("!");
                String zipFileName = split2[0];
                String sresource = split2[1];

                System.out.printf("After split zip file name = %s," +
                        " \nresource in zip %s \n", zipFileName, sresource);


                /* Open up the zip file. */
                ZipFile zipFile = new ZipFile(zipFileName);


                /*  Iterate through the entries.  */
                Enumeration entries = zipFile.entries();

                while (entries.hasMoreElements()) {
                    ZipEntry entry = entries.nextElement();
                    /* If it is a directory, then skip it. */
                    if (entry.isDirectory()) {
                        continue;
                    }

                    String entryName = entry.getName();
                    System.out.printf("zip entry name %s \n", entryName);

                    /* If it does not start with our someResource String
                       then it is not our resource so continue.
                    */
                    if (!entryName.startsWith(someResource)) {
                        continue;
                    }


                    /* the fileName part from the entry name.
                     * where /foo/bar/foo/bee/bar.txt, bar.txt is the file
                     */
                    String fileName = entryName.substring(entryName.lastIndexOf("/") + 1);
                    System.out.printf("fileName %s \n", fileName);

                    /* See if the file starts with our namespace and ends with our extension.        
                     */
                    if (fileName.startsWith(namespace) && fileName.endsWith(".txt")) {


                        /* If you found the file, print out 
                           the contents fo the file to System.out.*/
                        try (Reader reader = new InputStreamReader(zipFile.getInputStream(entry))) {
                            StringBuilder builder = new StringBuilder();
                            int ch = 0;
                            while ((ch = reader.read()) != -1) {
                                builder.append((char) ch);

                            }
                            System.out.printf("zip fileName = %s\n\n####\n contents of file %s\n###\n", entryName, builder);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }

                    //use the entry to see if it's the file '1.txt'
                    //Read from the byte using file.getInputStream(entry)
                }

            }


        }

        /**
         * The file was on the file system not a zip file,
         * this is here for completeness for this example.
         * otherwise.
         *
         * @param resource
         * @param namespace
         * @throws Exception
         */
        private static void handleFile(URL resource, String namespace) throws Exception {
            System.out.println("Handle this resource as a file " + resource);
            URI uri = resource.toURI();
            File file = new File(uri.getPath());


            if (file.isDirectory()) {
                for (File childFile : file.listFiles()) {
                    if (childFile.isDirectory()) {
                        continue;
                    }
                    String fileName = childFile.getName();
                    if (fileName.startsWith(namespace) && fileName.endsWith("txt")) {

                        try (FileReader reader = new FileReader(childFile)) {
                            StringBuilder builder = new StringBuilder();
                            int ch = 0;
                            while ((ch = reader.read()) != -1) {
                                builder.append((char) ch);

                            }
                            System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", childFile, builder);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }

                    }

                }
            } else {
                String fileName = file.getName();
                if (fileName.startsWith(namespace) && fileName.endsWith("txt")) {

                    try (FileReader reader = new FileReader(file)) {
                        StringBuilder builder = new StringBuilder();
                        int ch = 0;
                        while ((ch = reader.read()) != -1) {
                            builder.append((char) ch);

                        }
                        System.out.printf("fileName = %s\n\n####\n contents of file %s\n###\n", fileName, builder);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }

                }

            }
        }

    }


   

Qui puoi vedere un esempio più completo con l'output di esempio.

Al di fuori della tua tecnica, perché non utilizzare Java standard Classe JarFile per ottenere i riferimenti che desideri? Da lì la maggior parte dei tuoi problemi dovrebbe andare via.

Se utilizzi ampiamente le risorse, potresti prendere in considerazione l'utilizzo   Commons VFS .

Supporta anche:  * File locali  * FTP, SFTP  * HTTP e HTTPS  * File temporanei " normale FS supportato)  * Zip, Jar e Tar (non compresso, tgz o tbz2)  * gzip e bzip2  * risorse  * ram - " ramdrive "  * mime

C'è anche JBoss VFS - ma non è molto documentato.

Ho 2 file CSV che utilizzo per leggere i dati. Il programma java viene esportato come file jar eseguibile. Quando lo esporti, capirai che non esporta le tue risorse con esso.

Ho aggiunto una cartella sotto il progetto chiamata data in eclipse. In quella cartella ho archiviato i miei file CSV.

Quando devo fare riferimento a quei file, lo faccio in questo modo ...

private static final String ZIP_FILE_LOCATION_PRIMARY = "free-zipcode-database-Primary.csv";
private static final String ZIP_FILE_LOCATION = "free-zipcode-database.csv";

private static String getFileLocation(){
    String loc = new File("").getAbsolutePath() + File.separatorChar +
        "data" + File.separatorChar;
    if (usePrimaryZipCodesOnly()){              
        loc = loc.concat(ZIP_FILE_LOCATION_PRIMARY);
    } else {
        loc = loc.concat(ZIP_FILE_LOCATION);
    }
    return loc;
}

Quindi quando metti il ??jar in una posizione in modo che possa essere eseguito tramite la riga di comando, assicurati di aggiungere la cartella dei dati con le risorse nella stessa posizione del file jar.

Ecco un codice di esempio su come leggere correttamente un file all'interno di un file jar (in questo caso, il file jar in esecuzione corrente)

Cambia l'eseguibile con il percorso del tuo file jar se non è quello corrente in esecuzione.

Quindi modificare il filePath nel percorso del file che si desidera utilizzare all'interno del file jar. OSSIA se il tuo file è in

  

someJar.jar \ img \ test.gif

. Imposta filePath su " img \ test.gif "

File executable = new File(BrowserViewControl.class.getProtectionDomain().getCodeSource().getLocation().toURI());
JarFile jar = new JarFile(executable);
InputStream fileInputStreamReader = jar.getInputStream(jar.getJarEntry(filePath));
byte[] bytes = new byte[fileInputStreamReader.available()];

int sizeOrig = fileInputStreamReader.available();
int size = fileInputStreamReader.available();
int offset = 0;
while (size != 0){
    fileInputStreamReader.read(bytes, offset, size);
    offset = sizeOrig - fileInputStreamReader.available();
    size = fileInputStreamReader.available();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top