문제

Desktop 응용 프로그램으로 실행되는 별도의 JAR에서 JAR 파일 내에서 XML 파일에 액세스하려고합니다. 필요한 파일로 URL을 가져올 수 있지만 FilerEader (문자열로)를 전달하면 "파일 이름, 디렉토리 이름 또는 볼륨 레이블 구문이 올바르지 않습니다."

참조 지점으로, 동일한 항아리에서 이미지 리소스를 읽고 URL을 ImageICon 생성자로 전달하는 데 어려움이 없습니다. 이것은 URL을 얻는 데 사용하는 방법이 올바른 것으로 나타났습니다.

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

서비스 로더 클래스 내에서

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

이 기술을 사용하여 XML 파일을 읽는 데 무엇이 문제입니까?

도움이 되었습니까?

해결책 4

문제는 XMLREADER의 구문 분석 방법을 호출하는 데 너무 멀리 가고 있다는 것이 었습니다. 구문 분석 방법은 입력 소스를 수용하므로 Filereader를 사용할 이유가 없었습니다. 위의 코드의 마지막 줄을 변경합니다

xr.parse( new InputSource( filename ));

잘 작동합니다.

다른 팁

사용하고 싶은 것 같습니다 java.lang.Class.getResourceAsStream(String), 보다

http://java.sun.com/javase/6/docs/api/java/lang/class.html#getresourceasstream(java.lang.string)

이것이 바탕 화면 또는 웹 앱인지는 말하지 않습니다. 나는 그것을 사용할 것이다 getResourceAsStream() 데스크톱이거나 웹 앱인 경우 적절한 클래스 로더의 메소드.

마치 당신이 사용하는 것처럼 보입니다 URL.toString 결과에 대한 논쟁으로 결과 FileReader 건설자. URL.toString 약간 깨졌고 대신 일반적으로 사용해야합니다. url.toURI().toString(). 어쨌든 문자열은 파일 경로가 아닙니다.

대신, 당신은 다음과 같습니다.

  • 통과하십시오 URL 에게 ServicesLoader 그리고 전화하게하십시오 openStream 또는 유사합니다.
  • 사용 Class.getResourceAsStream 그리고 아마도 스트림을 넘어서서 InputSource. (API가 약간 지저분하므로 Nulls를 확인해야합니다.)

동일한 리소스가 여러 Jar 파일에있는 경우 한 가지 문제가 무엇인지 지적하고 싶습니다. /org/node/foo.txt를 읽고 싶지만 하나의 파일이 아니라 각 JAR 파일에서 읽으려고한다고 가정 해 봅시다.

나는이 같은 문제를 여러 번 전에 실행했습니다. 나는 JDK 7에서 누군가가 ClassPath 파일 시스템을 작성하기를 바랐지만 아직 아님.

Spring에는 ClassPath 리소스를 아주 잘로드 할 수있는 리소스 클래스가 있습니다.

나는 여러 개의 JAR 파일을 형성하는이 문제를 해결하는이 문제를 해결하기 위해 약간의 프로토 타입을 작성했습니다. 프로토 타입은 모든 에지 케이스를 처리하지는 않지만 JAR 파일에있는 디렉토리에서 리소스를 찾는 것을 처리합니다.

나는 스택 오버플로를 꽤 언젠가 사용했습니다. 이것은 내가 질문에 대답 한 것을 기억하는 두 번째 대답이므로 너무 오래 가면 용서하십시오 (내 본성입니다).

이것은 프로토 타입 리소스 리더입니다. 프로토 타입에는 강력한 오류 확인이 없습니다.

설정 한 두 개의 프로토 타입 JAR 파일이 있습니다.

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

JAR 파일에는 각각/org/node/호출 Resource.txt 아래에 파일이 있습니다.

이것은 ClassPath : // 핸들러가 어떻게 보일지에 대한 프로토 타입 일뿐입니다. 또한이 프로젝트의 현지 리소스에 Resource.foo.txt도 있습니다.

그것은 그들 모두를 집어 들고 인쇄합니다.

   

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

                }

            }
        }

    }


   

샘플 출력으로 여기에서 전체 예제를 볼 수 있습니다.

기술 이외의 표준 Java를 사용하지 않는 이유 Jarfile 클래스 원하는 참조를 얻으려면? 거기에서 대부분의 문제는 사라져야합니다.

리소스를 광범위하게 사용하는 경우 사용을 고려할 수 있습니다. 커먼즈 VFS.

또한 지원 : * 로컬 파일 * ftp, sftp * http 및 https * 임시 파일 "정상적인 fs backed) * zip, jar and tar (압축되지 않은, tgz 또는 tbz2) * gzip 및 bzip2 * ram -"ramdrive " * mime

또한 있습니다 Jboss VFS - 그러나 그것은별로 문서화되지 않았습니다.

데이터를 읽는 데 사용하는 2 개의 CSV 파일이 있습니다. Java 프로그램은 런닝 가능한 JAR 파일로 내보내집니다. 수출하면 자원을 내보내지 않는다는 것을 알게 될 것입니다.

Eclipse에서 Data라는 프로젝트에 폴더를 추가했습니다. 해당 폴더에서 CSV 파일을 저장했습니다.

그 파일을 참조해야 할 때 나는 이렇게합니다 ...

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

그런 다음 JAR을 위치에 넣어 CommandLine을 통해 실행할 수 있으면 자원이있는 데이터 폴더를 JAR 파일과 동일한 위치에 추가하십시오.

다음은 JAR 파일 내부에서 파일을 올바르게 읽는 방법에 대한 샘플 코드입니다 (이 경우 현재 실행중인 JAR 파일).

현재 실행중인 경우 JAR 파일의 경로로 실행 파일을 변경하십시오.

그런 다음 FilePath를 JAR 파일 내부에서 사용하려는 파일의 경로로 변경하십시오. 즉, 파일이있는 경우

somejar.jar img test.gif

. FilePath를 "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();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top