I want to load all resource bundle properties from classpath, so that I can show supported languages. I got a reference from here and tried 1st solution. It works file when I run my code from eclipse. But when I create executable jar file, it could not read files. I don't know why behavior is different while running from command java -jar AppName.jar
My Code Is:
public static List<String> getResourceFiles(String path) throws IOException
{
List<String> filenames = new ArrayList<>();
InputStream in = getResourceAsStream(path);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
System.out.println("br = " + br.readLine());
String resource;
while ((resource = br.readLine()) != null)
{
filenames.add(resource);
}
return filenames;
}
private static InputStream getResourceAsStream(String resource)
{
final InputStream in = getContextClassLoader().getResourceAsStream(resource);
System.out.println("input stream = " + in);
return in == null ? FileUtil.class.getResourceAsStream(resource) : in;
}
private static ClassLoader getContextClassLoader()
{
return Thread.currentThread().getContextClassLoader();
}
Here I noticed that InputStream is null when I run from command, but while running from eclipse InputStream is not null.
How to solve this problem so that I can read resource files when running from command also?
I found solution. Below code worked for me:
public static String[] getResourceListing(Class clazz, String path) throws URISyntaxException, IOException
{
URL dirURL = clazz.getClassLoader().getResource(path);
if (dirURL != null && dirURL.getProtocol().equals("file"))
{
/* A file path: easy enough */
return new File(dirURL.toURI()).list();
}
if (dirURL == null)
{
/*
* In case of a jar file, we can't actually find a directory. Have to assume the
* same jar as clazz.
*/
String me = clazz.getName().replace(".", "/") + ".class";
dirURL = clazz.getClassLoader().getResource(me);
}
if (dirURL.getProtocol().equals("jar"))
{
/* A JAR path */
String jarPath = dirURL.getPath().substring(5, dirURL.getPath().indexOf("!")); // strip out only the JAR file
JarFile jar = new JarFile(URLDecoder.decode(jarPath, "UTF-8"));
Enumeration<JarEntry> entries = jar.entries(); // gives ALL entries in jar
Set<String> result = new HashSet<String>(); // avoid duplicates in case it is a subdirectory
while (entries.hasMoreElements())
{
String name = entries.nextElement().getName();
if (name.startsWith(path))
{ // filter according to the path
String entry = name.substring(path.length());
int checkSubdir = entry.indexOf("/");
if (checkSubdir >= 0)
{
// if it is a subdirectory, we just return the directory name
entry = entry.substring(0, checkSubdir);
}
result.add(entry);
}
}
return result.toArray(new String[result.size()]);
}
throw new UnsupportedOperationException("Cannot list files for URL " + dirURL);
}
Related
I packaged my Spring Boot project into a JAR using maven. I want to read the names of all directories under "static/foo" in the resources folder.
Tried the following using the Apache Commons library:
String fooPath = "static/foo/";
List<String> fooFolders = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream(fooPath), Charsets.UTF_8);
// The fooFolders list is empty ...
UPDATE
This solution worked (slightly modified from https://stackoverflow.com/a/48190582/1427624) using JarFile:
String fooPath = "static/foo";
URL url = Thread.currentThread().getContextClassLoader().getResource(fooPath);
// Not running from JAR
if (url.getProtocol().equals("file"))
{
try {
// Get list of subdirectories' folder names
List<String> fooFolders = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream(fooPath), Charsets.UTF_8);
// Loop subdirectories
for (String fooFolder : fooFolders) {
// The current subdirectory path
String fooFolderPath = fooPath + "/" + fooFolder;
// Loop all files in this subdirectory, if needed
List<String> fooFiles = IOUtils.readLines(this.getClass().getClassLoader().getResourceAsStream(fooFolderPath), Charsets.UTF_8);
for (String fooFile : fooFiles) {
// The updated path of the file
String fooFilePath = fooFolderPath + "/" + fooFile;
// Read the file's content
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fooFilePath);
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer, Charsets.UTF_8);
String fileContent = writer.toString();
}
}
}
catch (IOException e) {
e.printStackTrace();
}
}
// Running from JAR
else if (url.getProtocol().equals("jar")) {
String dirname = fooPath + "/";
String path = url.getPath();
String jarPath = path.substring(5, path.indexOf("!"));
List<String> fooFolders = new ArrayList<String>();
HashMap<String, List<String>> fooFiles = new HashMap<String, List<String>>();
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 jarEntryName = entry.getName();
String updated_dir_name = "BOOT-INF/classes/" + dirname;
// Only get files that are in the directory we require (fooPath)
if (jarEntryName.startsWith(updated_dir_name) && !dirname.equals(updated_dir_name)) {
// Get the resource URL
URL resourceURL = Thread.currentThread().getContextClassLoader().getResource(jarEntryName);
// Files only
if (!jarEntryName.endsWith("/")) {
// Split the foo number and the file name
String[] split = jarEntryName.split("/");
// First level subdirectories inside fooPath
// BOOT-INF/classes/static/foo/1/myfile.html
// We want to read the folder name "1"
String folderName = split[split.length - 2];
// If you want to read this file
// Read the file's content
// InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceURL);
}
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Sounds like this could be solved by https://stackoverflow.com/a/3923685/7610371
The "core" bits from the answer above:
InputStream resourceStream = this.getClass().getClassLoader().getResourceAsStream(fooPath);
BufferedReader br = new BufferedReader(new InputStreamReader(resourceStream))
String resource;
while ((resource = br.readLine()) != null) {
// ... resource is the next filename; you can add it to an array
// or use it here
}
I think you should use FileUtils instead.
In particular, the method listFilesAndDirs with the filter DirectoryFileFilter.
You can also simply do the below :
File f = new File("static/foo/");
File[] arr = f.listFiles();
for (File file : arr) {
if (file.isDirectory())
System.out.println(file);
}
I have the local server mockftpserver, and in the server there are couple of files and they are protected with a prefix '._' and the method to protect from getting those files is the following :
protected String getRealPath(Session session, String path) {
String currentDirectory = (String) session.getAttribute(SessionKeys.CURRENT_DIRECTORY);
String result;
if (path == null) {
result = currentDirectory;
}
else if (getFileSystem().isAbsolute(path)) {
result = path;
}
else {
result = getFileSystem().path(currentDirectory, path);
}
return result.replace("._", "");
}
I tried to list the files in the FTP server I got them but the protected ones like '._passwrd' I was not able to see it.
I used the normal method to get the file list:
boolean login = ftpClient.login("user", "password");
if (login) {
System.out.println("Connection established...");
FTPFile[] files = ftpClient.listFiles();
for (FTPFile file : files) {
if (file.getType() == FTPFile.FILE_TYPE) {
System.out.println("File Name: "
+ file.getName()
+ " File Size: " );
}
}
String[] fil = ftpClient.listNames();
if (files != null && fil.length > 0) {
for (String aFile: fil) {
System.out.println(aFile);
}
}
BufferedReader reader = null;
String firstLine = null;
try {
InputStream stream =
ftpClient.retrieveFileStream("._"+"._passwd");
reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
firstLine = reader.readLine();
} finally {
if (reader != null)
try {
reader.close();
} catch (IOException logOrIgnore) {}
}
}
But thinking that the method will only check the name once, so if I added the ._ once again it should work. Although it did not or I could not apply it in the right way.
i don't know about Java but in Python i solved similar task in the following way:
i used: FTP server, Python 2.7.12, library 'ftplib'
so i show just needed part with comments:
#while customer list not empty
while self.customerDirs:
#create connect to root
self.connection.cwd("/")
#choose customer
customer = self.customerDirs.pop()
try:
#go inside to customer's folder
self.connection.cwd(customer)
#for all folders inside
for dir in self.connection.nlst():
#go inside
self.connection.cwd(dir)
#create empty list
hiddenList = []
#create variable which contains path
pathDir = self.connection.pwd()
#write to list hidden files
self.connection.retrlines("LIST -a", hiddenList.append)
for entry in hiddenList:
#split value and take file name
entrySplit = entry.split(' ')[-1]
#cheсk file name
if entrySplit not in ['.', '..'] and entrySplit.startswith('.'):
#all necessary files are sent to method which will delete it (lool like: /customer/folder/.hidden_file.hid)
self.ftp_delete_file('/'.join([pathDir, entrySplit]))
#return to step up
self.connection.cwd("..")
that all, i hope it will be helpful information
You should set your ftpClient to list hidden Files before listing the files, so:
ftpClient.setListHiddenFiles(true);
FTPFile[] files = ftpClient.listFiles();
My program displays elements read from a text file. The text files will be stored in a folder found in the package folder containing the .java and .class files so they can be embedded in the jar.
I'm trying to get the application to read the text files properly for both situations
Running from the IDE (Netbeans)
Running from the JAR
Currently I can do point one with no problem, but the code reads using File where as the way I am seeing how to do it with Jars is using InputStream.
The functions which work for the IDE runs
public void loadWidgets() {
ArrayList<String> results = new ArrayList<>();
String dir = new File("").getAbsolutePath() + "/src/Creator/textFiles/widgets/;
System.out.println(dir);
getWidgetFiles(dir, results);
results.stream().forEach((s) -> {
readFile(s); // given a string and it opens the file using a Scanner
});
updateWidgetVariables(); // gui updates
}
public void getWidgetFiles(String dirName, ArrayList<String> filePaths) {
File directory = new File(dirName);
File[] files = directory.listFiles();
for (File file : files) {
if (file.isFile()) {
filePaths.add(file.getName() + "," + file.getAbsolutePath());
} else if (file.isDirectory()) {
getWidgetFiles(file.getAbsolutePath(), filePaths);
}
}
}
So I have a bunch of text files organized by the type of widget it is, so I am running through the /widgets/ directory to find all the text files.
The problem I'm having is how I can go through the directories and files of a Jar? Can they be converted to a file, or read into a string?
I got this code from this question and it can read the files, but I dont know how I can open them using a new Scanner(file); code
CodeSource src = WidgetPanel.class.getProtectionDomain().getCodeSource();
try {
System.out.println("Inside try");
List<String> list = new ArrayList<>();
if (src != null) {
URL jar = src.getLocation();
ZipInputStream zip = new ZipInputStream(jar.openStream());
ZipEntry ze = null;
System.out.println(jar.getPath());
System.out.println(zip.getNextEntry());
while ((ze = zip.getNextEntry()) != null) {
String entryName = ze.getName();
System.out.println("Entry name: " + entryName);
if (entryName.startsWith("Creator/textFiles/widgets") && entryName.endsWith(".txt")) {
list.add(entryName);
System.out.println("Added name: " + entryName);
}
}
list.stream().forEach((s) -> {
readFile(s);
});
updateWidgetVariables();
} else {
System.out.println("Src null");
}
}catch (IOException e) {
System.out.println(e.getMessage());
}
Try and obtain a FileSystem associated with your source; the matter then becomes pretty simple. Here is an illustration of how to read, as text, all files from a given FileSystem:
private static final BiPredicate<Path, BasicFileAttributes> FILES
= (path, attrs) -> attrs.isRegularFile();
private static void readAllFilesAsText(final List<Path> paths)
throws IOException
{
for (final Path path: paths)
try (
final Stream<String> stream = Files.lines(path);
) {
stream.forEach(System.out::println);
}
}
private static List<Path> getAllFilesFromFileSystems(final FileSystem fs,
final String pathPrefix)
{
final Path baseDir = fs.getPath(pathPrefix);
try (
final Stream<Path> files = Files.find(baseDir, Integer.MAX_VALUE,
FILES);
) {
return files.collect(Collectors.toList());
}
}
Why the mix of "old style" for loops and "new style" lambdas: it is because lambdas just don't handle checked exceptions... Which means you have to do it. For a workaround, see here.
But the gist of it here is to be able to create a FileSystem out of your sources, and you can do it; yes, you can read jars as such. See here.
I was able to find a solution using the functions I already had.
I first check to see if the text file can be found normally (Run from an IDE). If a file not found exception occurs, it sets ide = false so it tries to read from the jar.
public void loadWidgets() {
boolean ide = true;
String path = "textFiles/widgets/";
ArrayList<String> results = new ArrayList<>();
String dir = new File("").getAbsolutePath() + "/src/Creator/" + path;
try {
getWidgetFiles(dir, results);
results.stream().forEach((s) -> {
readFile(s);
});
updateWidgetVariables();
} catch (FileNotFoundException e) {
System.out.println(e.getMessage());
ide = false;
}
if (!ide) {
CodeSource src = WidgetPanel.class.getProtectionDomain().getCodeSource();
try {
List<String> list = new ArrayList<>();
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("Creator/textFiles/widgets") && entryName.endsWith(".txt")) {
// Wouldnt work until i added the "/" before the entryName
list.add("/"+ entryName);
System.out.println("Added name: " + entryName);
}
}
list.stream().forEach((s) -> {
readJarFile(s);
});
updateWidgetVariables();
} else {
System.out.println("Src null");
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
I then created a new readFile function for reading from a Jar
public void readJarFile(String result) {
String name = result.substring(result.lastIndexOf("/") + 1);
String entireWidget = "";
String line;
ArrayList<String> vars = new ArrayList<>();
int begin, end;
InputStream loc = this.getClass().getResourceAsStream(result);
try (Scanner scan = new Scanner(loc)) {
while (scan.hasNextLine()) {
line = scan.nextLine();
entireWidget += line;
while (line.contains("`%")) {
begin = line.indexOf("`%");
end = line.indexOf("%`") + 2;
vars.add(line.substring(begin, end));
//System.out.println("Variable added: " + line.substring(begin, end));
line = line.substring(end);
}
}
}
System.out.println(name + ": " + entireWidget);
Widget widget = new Widget(name, vars, entireWidget, result);
widgetList.put(name, widget);
}
Most of this answer is thanks to this question
Previously we had some zip files within our web application. We would want to pares a specific text document within the zip file. This wasn't a problem:
URL url = getClass().getResource(zipfile);
ZipFile zip = new ZipFile(url.getFile().replaceAll("%20", " "));
Entry entry = zip.getEntry("file.txt");
InputStream is = zip.getInputStream(entry);
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = reader.readLine();
while (line != null) {
// do stuff
}
However we've moved these zip files into another module and want to package them within a jar. Unfortunately, creating the ZipFile now fails. I can get an InputStream for the zip: but I have no way of getting an input stream for the entry itself.
InputStream is = getClass().getResourceAsStream(zipfile);
ZipInputStream zis = new ZipInputStream(is);
ZipEntry entry = zis.getNextEntry();
while (entry != null && !entry.getName().equals("file.txt")) {
entry = zis.getNextEntry();
}
but I have no way of getting an input stream for the entry itself. I tried finding the length of the entry and getting the next n bytes from the ZipInputStream but this didn't work for me. It seemed all bytes read were 0.
Is there a way round this or am I going to have to move the zip files back into the core project?
How about TrueZip? Using it you could simply open the zipped file as if it was located inside a directory.
new FileOutputStream("/path/to/some-jar.jar/internal/zip/file.zip/myfile.txt");
According to the docs, infinite nesting is also supported. I have yet to actually use this project, but it's been on my radar for a while and it seems applicable to your problem.
Project Site: http://truezip.java.net/ (edited)
entry can give you the inputstream of the inner-zip file.
InputStream innerzipstream = zip.getInputStream(entry);
So you can use
new ZipInputStream(innerzipstream);
and ask the ZipInputStream to retrieve the content of the inner-zip-file (in an ordered fashion, you don't have random access because it's a ZipInputStream)
Look at http://download.oracle.com/javase/1.4.2/docs/api/java/util/zip/ZipInputStream.html
Sequential zip access
As ZipInputStream is reading a zip file from an input stream it has to do things in order:
// DO THIS for each entry
ZipEntry e = zipInputStreamObj.getNextEntry();
e.getName // and all data
int size = e.getSize(); // the byte count
while (size > 0) {
size -= zipInputStreamObj.read(...);
}
zipInputStreamObj.closeEntry();
// DO THIS END
zipInputStreamObj.close();
Note: I don't know if ZipInputStream.getNextEntry() returns null when end of zip file is reached or not. I hope so because I don't know other way to realize when there are no more entries.
I have modified the Sequential Zip access code provided above:
File destFile = new File(destDir, jarName);
JarOutputStream jos = new JarOutputStream(new FileOutputStream(destFile));
JarInputStream jis = new JarInputStream(is);
JarEntry jarEntry = jis.getNextJarEntry();
for (; jarEntry != null ; jarEntry = jis.getNextJarEntry()) {
jos.putNextEntry(new JarEntry(jarEntry.getName()));
if(jarEntry.isDirectory()) {
continue;
}
int bytesRead = jis.read(buffer);
while(bytesRead != -1) {
jos.write(buffer, 0, bytesRead);
bytesRead = jis.read(buffer);
}
}
is.close();
jis.close();
jos.flush();
jos.closeEntry();
jos.close();
In the above code, I am trying to copy a Jar file inside another Jar file to a folder in file system.
'is' is the input stream to the jar file inside another jar file (jar.getInputStream("lib/abcd.jar"))
it is also possible to parse the string and open an ZipInputStream on another ZipInputStream and set the entry to the file inside.
e.g. you have the String like above "path/to/some-jar.jar/internal/zip/file.zip/myfile.txt"
private static final String[] zipFiles = new String[] { ".zip", ".jar" };
public static InputStream getResourceAsStream(final String ref) throws IOException {
String abstractPath = ref.replace("\\", "/");
if (abstractPath.startsWith("/")) {
abstractPath = abstractPath.substring(1);
}
final String[] pathElements = abstractPath.split("/");
return getResourceAsStream(null, pathElements);
}
private static InputStream getResourceAsStream(final ZipInputStream parentStream, final String[] pathElements)
throws IOException {
if (pathElements.length == 0) return parentStream;
final StringBuilder nextFile = new StringBuilder();
for (int index = 0; index < pathElements.length; index++) {
final String pathElement = pathElements[index];
nextFile.append((index > 0 ? "/" : "") + pathElement);
if (pathElement.contains(".")) {
final String path = nextFile.toString();
if (checkForZip(pathElement)) {
final String[] restPath = new String[pathElements.length - index - 1];
System.arraycopy(pathElements, index + 1, restPath, 0, restPath.length);
if (parentStream != null) {
setZipToEntry(parentStream, path);
return getResourceAsStream(new ZipInputStream(parentStream), restPath);
} else return getResourceAsStream(new ZipInputStream(new FileInputStream(path)), restPath);
} else {
if (parentStream != null) {
setZipToEntry(parentStream, path);
return parentStream;
} else return new FileInputStream(path);
}
}
}
throw new FileNotFoundException("File not found: " + nextFile.toString());
}
private static void setZipToEntry(final ZipInputStream in, final String name) throws IOException {
ZipEntry entry;
while ((entry = in.getNextEntry()) != null) {
if (entry.getName().equals(name)) return;
}
throw new FileNotFoundException("File not found: " + name);
}
private static boolean checkForZip(final String ref) {
for (final String zipFile : zipFiles) {
if (ref.endsWith(zipFile)) return true;
}
return false;
}
I have a file in a JAR file. It's 1.txt, for example.
How can I access it? My source code is:
Double result=0.0;
File file = new File("1.txt")); //how get this file from a jar file
BufferedReader input = new BufferedReader(new FileReader(file));
String line;
while ((line = input.readLine()) != null) {
if(me==Integer.parseInt(line.split(":")[0])){
result= parseDouble(line.split(":")[1]);
}
}
input.close();
return result;
If your jar is on the classpath:
InputStream is = YourClass.class.getResourceAsStream("1.txt");
If it is not on the classpath, then you can access it via:
URL url = new URL("jar:file:/absolute/location/of/yourJar.jar!/1.txt");
InputStream is = url.openStream();
You can't use File, since this file does not exist independently on the file system. Instead you need getResourceAsStream(), like so:
...
InputStream in = getClass().getResourceAsStream("/1.txt");
BufferedReader input = new BufferedReader(new InputStreamReader(in));
...
A Jar file is a zip file.....
So to read a jar file, try
ZipFile file = new ZipFile("whatever.jar");
if (file != null) {
ZipEntries entries = file.entries(); //get entries from the zip file...
if (entries != null) {
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
//use the entry to see if it's the file '1.txt'
//Read from the byte using file.getInputStream(entry)
}
}
}
Hope this helps.
Something similar to this answer is what you need.
You need to pull the file out of the archive in that special way.
BufferedReader input = new BufferedReader(new InputStreamReader(
this.getClass().getClassLoader().getResourceAsStream("1.txt")));
private String loadResourceFileIntoString(String path) {
//path = "/resources/html/custom.css" for example
BufferedReader buffer = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(path)));
return buffer.lines().collect(Collectors.joining(System.getProperty("line.separator")));
}
This worked for me to copy an txt file from jar file to another txt file
public static void copyTextMethod() throws Exception{
String inputPath = "path/to/.jar";
String outputPath = "Desktop/CopyText.txt";
File resStreamOut = new File(outputPath);
int readBytes;
JarFile file = new JarFile(inputPath);
FileWriter fw = new FileWriter(resStreamOut);
try{
Enumeration<JarEntry> entries = file.entries();
while (entries.hasMoreElements()){
JarEntry entry = entries.nextElement();
if (entry.getName().equals("readMe/tempReadme.txt")) {
System.out.println(entry +" : Entry");
InputStream is = file.getInputStream(entry);
BufferedWriter output = new BufferedWriter(fw);
while ((readBytes = is.read()) != -1) {
output.write((char) readBytes);
}
System.out.println(outputPath);
output.close();
}
}
} catch(Exception er){
er.printStackTrace();
}
}
}
I have run into this same issue several times before.
I was hoping in JDK 7 that someone would write a classpath filesystem, but alas not yet.
Spring has the Resource class which allows you to load classpath resources quite nicely.
The answers have been very good, but I thought I could add to the discussion with showing an example that works with files and directories that are classpath resources.
I wrote a little prototype to solve this very problem. The prototype does not handle every edge case, but it does handle looking for resources in directories that are in the jar files.
I have used Stack Overflow for quite sometime. This is the first time that I remember answering a question so forgive me if I go to long (it is my nature).
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();
}
}
}
}
}
You can see a fuller example here with the sample output.