I am trying to create a simple function which copies or merge two or more folder files into one single folder.
I started with below. I thought to post here to get a better quality code.
public void copyDifferentFolderFilesIntoOne(String mergedFolderStr,String ... foldersStr)
{
File mergedFolder= new File(mergedFolderStr);
for(String folder: foldersStr)
{
//copy folder's files into mergedFolder
}
}
When there is a conflict in file copying (i.e. file with same name exists on two or more folder) I want the file with latest timestamp get copied in mergedFolder.
Do you know the best way to merge two or more folders files into one?
Let me know if question is not clear.
You can create a Map<String, File> of the files you want to copy by traversing the merged dirs and keeping the newest files. Then you can copy the files you have in a map.
A sample code (haven't tried it) might look like this:
public void copyDifferentFolderFilesIntoOne(String mergedFolderStr,
String... foldersStr) {
final File mergedFolder = new File(mergedFolderStr);
final Map<String, File> filesMap = new HashMap<String, File> ();
for (String folder : foldersStr) {
updateFilesMap(new File (folder), filesMap, null);
}
for (final Map.Entry<String, File> fileEntry : filesMap.entrySet()) {
final String relativeName = fileEntry.getKey();
final File srcFile = fileEntry.getValue();
FileUtils.copyFile (srcFile, new File (mergedFolder, relativeName));
}
}
private void updateFilesMap(final File baseFolder, final Map<String, File> filesMap,
final String relativeName) {
for (final File file : baseFolder.listFiles()) {
final String fileRelativeName = getFileRelativeName (relativeName, file.getName());
if (file.isDirectory()) {
updateFilesMap(file, filesMap, fileRelativeName);
}
else {
final File existingFile = filesMap.get (fileRelativeName);
if (existingFile == null || file.lastModified() > existingFile.lastModified() ) {
filesMap.put (fileRelativeName, file);
}
}
}
}
private String getFileRelativeName(final String baseName, final String fileName) {
return baseName == null ? fileName : baseName + "/" + fileName;
}
To copy file, look at Standard concise way to copy a file in Java?
To get timestamp, see File.lastModified()
Related
String folderpath = "G:\\AE_IntegrationComp";
//Above is Folder where is Different files are present
List <String>filet = new ArrayList<String>();
filet.add(".txt");
filet.add(".doc");
//extension which I added
for(String str : filet)
{
}
File directory = new File(folderpath);
for(File list : directory.listFiles())
{
if(list.getName().contains(""))
{
System.out.println(list.getName());
}
}
I have to check if Directory is empty or not
if not,
file extension in Arraylist should matched with extensions Are available in Directory
and print files that matched
What you wanna do is:
Iterate through all files into a directory (which you have done)
Check if it has a certain extension (it ends with a certain string)
Print the file name if that matches.
public class Main {
// Here we have a constant containing the interesting file extensions
public static final String[] extensions = new[] { ".txt", ".doc" };
// This helper function will tell us whether
// a file has one of the interesting file extensions
public static boolean matchesExtension(File file) {
for(String ext : extensions) {
if(file.getName().endsWith(ext)) {
return true;
}
}
return false;
}
public static void main(String[] args) {
String folderpath = "G:\\AE_IntegrationComp";
File directory = new File(folderpath);
// Iterate through all files in the directory
for(File file : directory.listFiles()){
if(matchesExtension(file)){
System.out.println(file.getName());
}
}
}
}
I have gone through the link of how to extract a .tar file and several link on SOF using Java.
However, I didnt find any which can relate to my concerns which is multilevel or nested .tar/.tgz/.zip file.
my concern is with something like below
Abc.tar.gz
--DEF.tar
--sample1.txt
--sample2.txt
--FGH.tgz
--sample3.txt
-sample4.txt
This is the simple one which I can give here . As it can be in any compressed combination with the folder like .tar inside .tar and .gz and again .tgz and so on....
My problem is I am able to extract till the first level using Apache Commons Compress library. that is if Abc.tar.gz gets extracted then in the destination/output folder its only DEF.tar available . beyond that my extraction is not working.
I tried to give the output of first to the input to the second on the fly but I got stuck with FileNotFoundException. As at that point of time output file would have not been in place and the second extraction not able to get the file.
Pseudocode:
public class CommonExtraction {
TarArchiveInputStream tar = null;
if((sourcePath.trim().toLowerCase.endsWith(".tar.gz")) || sourcePath.trim().toLowerCase.endsWith(".tgz")) {
try {
tar=new TarArchiveInputStream(new GzipCompressorInputStream(new BufferedInputStream(new FileInputStream(sourcePath))));
extractTar(tar,destPath)
} catch (Exception e) {
e.printStackTrace();
}
}
}
Public static void extractTar(TarArchiveInputStream tar, String outputFolder) {
try{
TarArchiveEntry entry;
while (null!=(entry=(TarArchiveEntry)tar.getNextTarEntry())) {
if(entry.getName().trim().toLowerCase.endsWith(".tar")){
final String path = outputFolder + entry.getName()
tar=new TarArchiveInputStream(new BufferedInputStream(new FileInputStream(path))) // failing as .tar folder after decompression from .gz not available at destination path
extractTar(tar,outputFolder)
}
extractEntry(entry,tar,outputFolder)
}
tar.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
Public static void extractEntry(TarArchiveEntry entry , InputStream tar, String outputFolder){
final String path = outputFolder + entry.getName()
if(entry.isDirectory()){
new File(path).mkdirs();
}else{
//create directory for the file if not exist
}
// code to read and write until last byte is encountered
}
}
Ps: please ignore the syntax and all in the code.
Try this
try (InputStream fi = file.getInputStream();
InputStream bi = new BufferedInputStream(fi);
InputStream gzi = new GzipCompressorInputStream(bi, false);
ArchiveInputStream archive = new TarArchiveInputStream(gzi)) {
withArchiveStream(archive, result::appendEntry);
}
As i see what .tar.gz and .tgz is same formats. And my method withArchiveEntry is:
private void withArchiveStream(ArchiveInputStream archInStream, BiConsumer<ArchiveInputStream, ArchiveEntry> entryConsumer) throws IOException {
ArchiveEntry entry;
while((entry = archInStream.getNextEntry()) != null) {
entryConsumer.accept(archInStream, entry);
}
}
private void appendEntry(ArchiveInputStream archive, ArchiveEntry entry) {
if (!archive.canReadEntryData(entry)) {
throw new IOException("Can`t read archive entry");
}
if (entry.isDirectory()) {
return;
}
// And for example
String content = new String(archive.readAllBytes(), StandardCharsets.UTF_8);
System.out.println(content);
}
You have a recursive problem, so you can use recursion to solve it. Here is some pseudocode to show how it can be done:
public class ArchiveExtractor
{
public void extract(File file)
{
List<File> files; // list of extracted files
if(isZip(file))
files = extractZip(file);
else if(isTGZ(file))
files = extractTGZ(file);
else if(isTar(file))
files = extractTar(file);
else if(isGZip(file))
files = extractGZip(file);
for(File f : files)
{
if(isArchive(f))
extract(f); // recursive call
}
}
private List<File> extractZip(File file)
{
// extract archive and return list of extracted files
}
private List<File> extractTGZ(File file)
{
// extract archive and return list of extracted files
}
private List<File> extractTar(File file)
{
// extract archive and return list of extracted files
}
private List<File> extractGZip(File file)
{
// extract archive and return list of extracted file
}
}
where:
isZip() tests if the file extension is zip
isTGZ() tests if the file extension is tgz
isTar() tests if the file extension is tar
isGZip() tests if the file extension is gz
isArchive() means isZip() || isTGZ() || isTar() || isGZip()
As for the directory where each archive is extracted: you are free to do as you want.
If you process test.zip for example, you may extract in the same directory as where the archive is,
or create the directory test and extract in it.
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)
So here is my problem:
I have here a program that gets all files and folders in a certian directory:
import java.io.File;
import java.util.ArrayList;
public class getFilesAndFolders {
private String[] filesAndFolders = {};
private ArrayList<String> filesAndFolders2 = new ArrayList<String>(filesAndFolders.length +1);
public String[] get(String location){
File files = new File(location);
File[] fList = files.listFiles();
for(File fileLoop : fList){
if(files.isDirectory()){
String placeHolder = fileLoop.getPath();
filesAndFolders2.add(placeHolder);
initialise();
}else if(files.isFile()){
String placeHolder = fileLoop.getPath();
filesAndFolders2.add(placeHolder);
initialise();
}
}
return filesAndFolders;
}
private void initialise() {
filesAndFolders = filesAndFolders2.toArray(new String[filesAndFolders2.size()]);
filesAndFolders2 = new ArrayList<String>(filesAndFolders.length +1);
}
}
I call it with this:
sample.get("sample//samples");
And it returns a nullPointerException at line 16. (The for loop)
Whereas when I type this:
private static Image n1 = new Image("sample//sample2//sample3.png");
The file would be found and the application would load fine. How can I make it so that this program returns something?
Ps: I got to to work before: But it was with a file outside the Jar file
Edit: I want to return the file list back as a String[]. Also, I don't want the computer to know beforehand what files exist there. (EG: If a files name is changed, the computer will still find it)
If I'm reading your question properly, you want a list of entries in a jar file, without knowing in advance what's in the jar file.
To get the the list of entries in a jar file, you can use the java.util.jar.JarFile and java.util.jar.JarEntry classes:
String jarFileName = ...
JarFile jar = new JarFile( jarFileName );
Enumeration<JarEntry> entries = jar.entries();
while ( entries.hasMoreElements() )
{
JarEntry entry = entries.nextElement();
String entryName = entry.getName();
// do something with the entryName String
...
// get an InputStream for the entry
InputStream is = jar.getInputStream( entry );
...
}
I am using Files.walk function to get the files present in a sub directory of a main directory. for example :
/path/to/stuff/foo/bar1/myfile.sql
/path/to/stuff/foo/bar1/myfiles.sql
/path/to/stuff/foo/bar2/myfile.sql
/path/to/stuff/foo/bar3/myfile.sql
/path/to/stuff/foo/bar4/myfile.sql
/path/to/stuff/foo/bar5/
/path/to/stuff/foo/bar6/myfile.sql
/path/to/stuff/foo/bar7/myfile.sql
/path/to/stuff/foo/bar8/myfile.sql
/path/to/stuff/foo/bar9/myfile.sql
this is my code :
Files.walk(Paths.get("/path/to/stuff")).forEach(filePath -> {
if (Files.isRegularFile(filePath)) {
buildFiles();
}
});
in the buildFiles i need to get the filename and the subfoldername and make that as a file name example loop 1 : path=/path/to/stuff/foo/bar1/myfile.sql and the filename should be foo_bar1.sql. How would i do that?
you have to create a file using the path. That will help you to manage your file. I guess you wonder if creating a file with
new file()
won't overwrite your file. Don't worry it won't It will help to have some sort of java reference to your file.
Files.walk(Paths.get("/path/to/stuff")).forEach(filePath -> {
if (Files.isRegularFile(filePath1)) {
File file1 = new File(filePath1);
String folderName = file.getName();
Files.walk(Paths.get("/path/to/stuff"+folderName)).forEach(filePath2 -> {
if (Files.isRegularFile(filePath2)) {
File file2 = new File(filePath2);
String subFolderName = file2.getName();
String result = folderName+subFolderName+".sql";
builFiles(result)
}
});
}
});