How to get absolute directory path from relative path + classloader - java

I have a class whose constructor receives a relative resources path (language properties files) and the corresponding classloader (the path is relative to the package of the classLoader):
public Language(String relDir, ClassLoader classLoader) {
...
}
Whithin that class I have a method that loads all found resource files (properties files such as MyFile_en_GB.properties), and it doesn't know whow many language resources there will be beforehand. It uses languagesDir as an absolute path for finding the resources.
private void loadLanguages() {
DirectoryStream.Filter<Path> filter = (path) -> {
return Files.isRegularFile(path) & path.getFileName()toString().startsWith("MyFile");
};
try (DirectoryStream<Path> stream = Files.newDirectoryStream(languagesDir, filter)) {
for (Path entry : stream) {
String fileName = entry.getFilename().toString();
...
loadPropertiesFile(filename)
}
} catch (..) {}
}
There, languagesDir works with an absolute path. However, when I tried:
String dir = classLoader.getResource(relDir).toString();
it throws an exception. I guess it is because it expects a file and not a directory
How can I get the absolute path of the resources? Should I try another aproach and work only with relative paths (how to do this)?
edit: About the exception:
classLoader.getResource(relDir) gives a null URL

try to use resourceFile.getName() after change URL to file.
URL resourceURL = classLoader.getResource(..);
File resourceFile = new File(new URL(resourceURL).toURI());
String fullPath = resourceFile.getName();

it throws an exception. I guess it is because it expects a file and
not a directory
If that is the case you can feed files instead directory. To get the absolute path you try as below
String dirPath = "C:\\Softwares";
File dir = new File( dirPath );
for ( String fileName : dir.list() ) {
File file = new File( dirPath + "\\" + fileName );
if ( file.isFile() ) {
// System.out.println( file.getAbsolutePath() );
String dir = classLoader.getResource( file.getAbsolutePath() ).toString();
}
}

Related

Reading Directory Contents From a JAR file

I am trying to write a code in a webapp, where I have a JAR file in my classpath. The objective is to check if the directory exists in the JAR. If yes, I need to save the all the contents of the files inside the JAR's directory in a HashMap<String, String>. The Key being the file name and the value being the contents of each file.
File directory = new File(getClass().getClassLoader().getResource(directoryPath).getPath());
System.out.println("PATH IS: " + directory.getPath());
// Check if dirPth exists and is a valid directory
if (!directory.isDirectory()) {
throw new AccessException("Directory \"" + directoryPath + "\" not valid");
}
// Obtain a list of all files under the dirPath
File [] fileList = directory.listFiles();
for (File file : fileList) {
if (file.isFile()) {
// Read the file
BufferedReader br = new BufferedReader(new FileReader(file));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
// Store the file data in the hash
entry.put(file.getName(), sb.toString);
}
}
The output of the direcotry.getPath() is:
file:\H:\apache-tomcat-9.0.27\lib\myConfigurationFiles.jar!\META-INF\Maintenance\xmlFiles\secondary
which is the right folder I am looking for.
Here the Map object is the "entry".
Now I am not sure why direcotry.isDirectory() returns false. Shouldn't it return true?
Now since its not crossing the first exception. I have no idea how it will behave after that. Any help would be appreciated.
getClass() is the wrong approach for jobs like this; it breaks if anybody subclasses. The proper way is to use MyClassName.class instead.
getClassLoader().getResource() is also the wrong approach; this breaks in exotic but possible cases where getClassLoader() returns null. Just use getResource and slightly change the path (add a leading slash, or, write the path relative to your class file).
You're turning the string file:\H:\apache-tomcat-9.0.27\lib\myConfigurationFiles.jar!\META-INF\Maintenance\xmlFiles\secondary into a filename and then asking if it is a directory. Of course it isn't; that isn't even a file. You need to do some string manipulation to extract the actual file out of it: You want just H:\apache-tomcat-9.0.27\lib\myConfigurationFiles.jar, feed that to the java.nio.file API, and then use that to ask if it is a file (it will never be a directory; jars are not directories).
Note that this will not work if the resource you're reading from isn't a jar. Note that the class loading API is abstracted: You could find yourself in the scenario where source files are generated from scratch or loaded out of a DB, with more exotic URLs being produced by the getResource method to boot. Thus, this kind of code simply won't work then. Make sure that's okay first.
Thus:
String urlAsString = MyClassName.class.getResource("MyClassName.class").toString(); // produces a link to yourself.
int start = urlAsString.startsWith("file:jar:") ? 8 : urlAsString.startsWith("file:") ? 4 : 0;
int end = urlAsString.lastIndexOf('!');
String jarFileLoc = urlAsString.substring(start, end);
if you want this to apply to actual directories (class files and such can come from dirs instead of files), you could do:
var map = new HashMap<String, String>();
Path root = Paths.get(jarFileLoc);
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
String content = new String(Files.readAllBytes(file), StandardCharsets.UTF_8);
map.put(root.relativize(file), content);
}
});
for a jar, which is really just a zip, it'll be more like:
var map = new HashMap<String, String>();
Path root = Paths.get(jarFileLoc);
try (var fileIn = Files.newInputStream(root)) {
ZipInputStream zip = new ZipInputStream(fileIn);
for (ZipEntry entry = zip.getNextEntry(); entry != null; entry = zip.getNextEntry()) {
String content = new String(zip.readAllBytes(), StandardCharsets.UTF_8);
map.put(entry.getName(), content);
}
}
Make sure you know what charsets are and that UTF_8 is correct here.
Given a java.nio.file.Path to the jar you want to search (jarPath), and a String for the absolute directory name within the jar (directory), this may work for you:
Map<String, String> map = new HashMap<>();
try (FileSystem fs = FileSystems.newFileSystem(jarPath, null)) {
Path dir = fs.getPath(directory);
if (Files.exists(dir)) {
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
map.put(file.toString(), Files.readString(file));
return super.visitFile(file, attrs);
}
});
}
}
Files.readString is available with Java 11+. For earlier versions, use:
new String(Files.readAllBytes(file), StandardCharsets.UTF_8)

Where to put resource in java project and how to read from resource

I am trying to read resources from my java project, I have placed properties files in resource/properties/name.properties. Following is the code what I return so far,want to read from relative path.
public void loadResource()
{
Properties config = new Properties();
final String dir = System.getProperty("user.dir");
System.out.println("current dir = " + dir);
InputStream in = getClass().getResourceAsStream(dir+"resource/properties/name.properties");
try
{
config.load(in);
}
catch(IOException ex)
{
Resources are always loaded from classpath.
If you specify relative path, then relative to the class, otherwise absolute on the classpath (not disk).
Your program is incorrect, you should use:
getClass().getResourceAsStream("/resource/properties/name.properties");

Moving files from one directory to another with Java NIO

I am using the NIO libraries but I am getting a strange error when I try to move files from one directory to another.
String yearNow = new SimpleDateFormat("yyyy").format(
Calendar.getInstance().getTime());
try {
DirectoryStream<Path> curYearStream =
Files.newDirectoryStream(sourceDir, "{" + yearNow + "*}");
//Glob for current year
Path newDir = Paths.get(sourceDir + "//" + yearNow);
if (!Files.exists(newDir) || !Files.isDirectory(newDir)) {
Files.createDirectory(newDir);
//create 2014 directory if it doesn't exist
}
}
Iterate over elements that start with "2014" and move them in the new directory (newDir, which is also called 2014)
for (Path p : curYearStream) {
System.out.println(p); //it prints out exactly the files that I need to move
Files.move(p, newDir); //java.nio.file.FileAlreadyExistsException
}
I get the java.nio.file.FileAlreadyExistsException because my folder (2014) already exists. What I actually want to do is move all the files that start with "2014" INSIDE the 2014 directory.
Better not going back to java.io.File and using NIO instead:
Path sourceDir = Paths.get("c:\\source");
Path destinationDir = Paths.get("c:\\dest");
try (DirectoryStream<Path> directoryStream = Files.newDirectoryStream(sourceDir)) {
for (Path path : directoryStream) {
System.out.println("copying " + path.toString());
Path d2 = destinationDir.resolve(path.getFileName());
System.out.println("destination File=" + d2);
Files.move(path, d2, REPLACE_EXISTING);
}
} catch (IOException ex) {
ex.printStackTrace();
}
Files.move is not equivalent to the mv command. It won't detect that the destination is a directory and move files into there.
You have to construct the full destination path, file by file. If you want to copy /src/a.txt to /dest/2014/, the destination path needs to be /dest/2014/a.txt.
You may want to do something like this:
File srcFile = new File("/src/a.txt");
File destDir = new File("/dest/2014");
Path src = srcFile.toPath();
Path dest = new File(destDir, srcFile.getName()).toPath(); // "/dest/2014/a.txt"
Continue with #Andrew's answer
If we use only Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING); then it will delete source directory because we only provide a directory path not an absolute path of a particular file. So it will also delete a source directory when operation will be done.
Let's say source path is /opt/src which contains a csv files and destination path is /opt/dst and I want to move all files from src to dst and I'm using Files.move(src, dst, StandardCopyOption.REPLACE_EXISTING); this then it will move all the files to dst but it will delete a src directory after moving all files because we didn't provide an absolute path of a each file for src as well as dst. We should have to provide src path like /opt/src/foo.csv and dst path like /opt/dst/foo.csv then and then it will not delete a source directory.
DirectoryStream used to iterate over the entries in a directory. A directory stream allows for the convenient use of the for-each construct to iterate over a directory. So we get an absolute path for src and we use resolve method for resolving an absolute path for dst.
Please refer DirectoryStream for more information.
Try this code:
public class App
{
public void moveFromSourceToDestination(String sourceName,String destinationName)
{
File mydir = new File(sourceName);
if (mydir.isDirectory())
{
File[] myContent = mydir.listFiles();
for(int i = 0; i < myContent.length; i++)
{
File file1 = myContent[i];
file1.renameTo(new File(destinationName+file1.getName()));
}
}
}
public static void main(String [] args)
{
App app = new App();
String sourceName = "C:\\Users\\SourceFolder";
String destinationName = "C:\\Users\\DestinationFolder\\";
app.moveFromSourceToDestination(sourceName,destinationName);
}
}
Using java.io.File, its as simple as this:
File srcFile = new File(srcDir, fileName);
srcFile.renameTo(new File(destDir, "a.txt"));

check if some folders exists java Android

I need check at least 4 directories if they exists and get the correct path in a variable for finnish my code.
But I don't know the correct way to do that.
Thanks for your help.
Here my code for check a single directory
final String uploadFilePath = "/mnt/sdcard/folder1/";
File f = new File(uploadFilePath);
if(f.exists() && f.isDirectory()){
Log.v("FILES", "EXIST");
}else{
Log.v("FILES", "DONT EXIST");
}
This way you can go on
String[] myDirectories = {"","",""......}; // your list of directories
for (String directory : myDirectories ) {
File file = new File(directory);
if(file.exists() && file.isDirectory())
// Do something you have found your directory
}
Is this enough?
Path uploadPath = Paths.get(uploadFilePath);
Path path = Files.exists(uploadPath) ? uploadPath : Files.createDirectory(uploadPath);
System.out.println(path);
Then to check for the N directories, put it in a loop maybe.
final String[] paths = { "C:/aa/", "C:/bb/", "C:/cc/", "C:/dd/"};
for (String path : paths) {
Path uploadPath = Paths.get(path);
if(Files.exists(uploadPath))
Files.createDirectory(uploadPath);
System.out.println(uploadPath);
}

Get a file from a given classpath

public String getQuery(String nameFile, Package pathFile)
{
// How to get on InputStrem nameFile and pathFile
}
I was not able to make it through classloader
String path = getClass().getPackage().getName().replace('.', File.pathSeparatorChar);
String file = path + "file.txt";
InputStream in = this.getClass().getClassLoader().getResourceAsStream(file);
return in = null
The pathSeparatorChar is : on Unix and ; on Windows. It has nothing to do with the char used to load resources from the ClassLoader, which is /, on all platforms.
Moreover, you forgot a separator between the path and the file name. It should be
String path = getClass().getPackage().getName().replace('.', '/');
String file = path + "/file.txt";
InputStream in = this.getClass().getClassLoader().getResourceAsStream(file);
Or, much simpler, since Class has a method which can load resources from the same package as the class directly:
InputStream in = this.getClass().getResourceAsStream("file.txt");

Categories