I have one folder which contains many sub-folders. To make it more clear here is an example of the folders:
Movies:
MovieTitle:
Moviefile.mp4 (Movie File)
MovieSubtitles.srt (Subtitles)
MovieSeries:
MovieTitle:
Moviefile.mp4
MovieSubtitles.srt
I need to rename each mp4 and srt file to the following "MovieTitle". If the movie is part of a series it should be named to Series "Title + Movie Title". Lets use Star Wars as an example for series and how to name. "Star Wars" would be the name of a directory in "Movies". In "Star Wars" are 6 Folders each with a mp4 and srt file in it. For episode 1 of star wars the mp4 and srt file should be renamed to: "Star Wars - Episode 1.mp4" and "Star Wars - Episode 1.srt". If Episode 1 was not part of series it should be named to just "Episode 1.mp4"
Here is the code that I have come up with so far:
public static void renaming(File[] files){
String dir1, dir2;
for(File movie: files){ //Main folder containing all of the movies.
dir1 = movie.getName();
for(File filesInMovie: movie.listFiles()){
if(filesInMovie.isDirectory()){ //This means that it is a series.
dir2 = filesInMovie.getName();
for(File i: filesInMovie.listFiles()){
i.renameTo(dir1 + " - " + dir2);
}
}else{
filesInMovie.renameTo(dir1)
}
}
}
}
I realize that renameTo is an actual function in Java. I thought it would rename files until I read what it actually does (which I am still a little fuzzy on). So my main question is how would I get this code to properly rename the files.
Just some extra things you should know:
One Directory Contains all of the movies.
There are possibilities for each folder in the movies folder
It has other folders in it (It is a series)
It has a mp4 and srt file in it
If you have any questions please ask!!!
File#getName() returns a String. You are using this to get the name of the current file and then attempting to rename the file using File#rename(String) where the method is actually defined as File#renameTo(File). That is it the argument is expected to be a file to where you are attempting to rename the file.
Some Suggestions:
Look at Files.move() use this to move the file to target - Link has example of this
Don't use the get name method for the first directory - use the file directly (Something like below but still not correct I think) and this is if you want the file in the same base directory movies
i.renameTo(new File(movie," - " + filesInMovie.getName() + ext);
Still needs work for extension of file ext however which will come from the file i
Using Guava and Java 7, here is what you can do:
public final class Renamer
{
private static final Joiner JOINER = Joiner.on(" - ");
private static final class RenamerVisitor
extends SimpleFileVisitor<Path>
{
private final Path baseDir;
private RenamerVisitor(final Path baseDir)
{
this.baseDir = baseDir;
}
#Override
public FileVisitResult visitFile(final Path file,
final BasicFileAttributes attrs)
throws IOException
{
final Path relpath = baseDir.relativize(file);
final String targetName
= JOINER.join(Iterables.transform(relpath,
Functions.toStringFunction()));
final Path dstPath = baseDir.resolve(targetName);
System.out.printf("'%s' -> '%s'\n", file, dstPath);
return FileVisitResult.CONTINUE;
}
}
public static void main(final String... args)
throws IOException
{
final Path baseDir = Paths.get("/home/fge/tmp/jsr203/docs");
Files.walkFileTree(baseDir, new RenamerVisitor(baseDir));
}
}
This is for my environment in a directory. Sample output:
[...]
'/home/fge/tmp/jsr203/docs/java/io/class-use/File.html' -> '/home/fge/tmp/jsr203/docs/java - io - class-use - File.html'
'/home/fge/tmp/jsr203/docs/java/io/class-use/FilePermission.html' -> '/home/fge/tmp/jsr203/docs/java - io - class-use - FilePermission.html'
'/home/fge/tmp/jsr203/docs/java/io/File.html' -> '/home/fge/tmp/jsr203/docs/java - io - File.html'
In order to make it use the "real thing", replace the System.out.println() in visitFile with Files.move() and you're done!
Of course, you can also choose to copy instead, or even create a (hard) link if your filesystem supports it.
Side note: unlike File's .renameTo(), Files.move() does not silently fail!
(and after that, you should drop Java 6's old file API fast)
Related
Browsing some answers I found that the following line should to the trick:
Files.copy(Paths.get(from), Paths.get(to),StandardCopyOption.REPLACE_EXISTING);
However, when I actually do provide some directory paths I get various exceptions or nothing is actually being copied, like for example:
kopiraj("C:/Users/Aleksije/Desktop/Rokovi/Rokovi 2016","C:/Users/Aleksije/Desktop/OVDE");
P.S. kopiraj(..) is a method in another class
public void kopiraj(String from, String to) throws IOException {
long t1 = System.nanoTime();
Files.copy(Paths.get(from), Paths.get(to),StandardCopyOption.REPLACE_EXISTING); //the line that matters
proteklo = t1 - System.nanoTime();
traverse(to);
}
After some reading I found that:
You can copy a file or directory by using the copy(Path, Path,
CopyOption...) method. The copy fails if the target file exists,
unless the REPLACE_EXISTING option is specified.
Directories can be copied. However, files inside the directory are not
copied, so the new directory is empty even when the original directory
contains files.
Thus I had to modify my approach to work as follows:
public void kopiraj(String from, String to) throws IOException {
File[] sadrzaj = new File(from).listFiles();
for(File f : sadrzaj) {
if(f.isFile()) {
sviFajlovi.add(f);
Files.copy(Paths.get(f.getAbsolutePath()), Paths.get(to + f.getName()), StandardCopyOption.REPLACE_EXISTING);
} else {
Files.copy(Paths.get(f.getAbsolutePath()), Paths.get(to + f.getName()), StandardCopyOption.REPLACE_EXISTING);
kopiraj(f.getAbsolutePath() + "/", to + f.getName() + "/");
}
}
}
To clarify for someone that might face the same issue:
Files.copy(Paths.get(f.getAbsolutePath()), Paths.get(to + f.getName()), StandardCopyOption.REPLACE_EXISTING);
When using copy from one directory to another, it is a must to provide the new filename in the destination directory, that's why I added the name of the file that is being copied to the destination. (Otherwise you'll lose your destination folder).
kopiraj(f.getAbsolutePath() + "/", to + f.getName() + "/");
When copying the contents of some sub-directory you usually want to keep the contents in there, thus I call the kopiraj() method with a new destination, which has been updated to copy to the now copied sub-directory.
Is there a way to access the file inside archive while ignoring file name case using TrueZip?
Imagine following zip archive with content:
MyZip.zip
-> myFolder/tExtFile.txt
-> anotherFolder/TextFiles/file.txt
-> myFile.txt
-> anotherFile.txt
-> OneMOREfile.txt
This is how it works:
TPath tPath = new TPath("MyZip.zip\\myFolder\\tExtFile.txt");
System.out.println(tPath.toFile().getName()); //prints tExtFile.txt
How to do the same but ignore all case, like this:
// note "myFolder" changed to "myfolder" and "tExtFile" to "textfile"
TPath tPath = new TPath("MyZip.zip\\myfolder\\textfile.txt");
System.out.println(tPath.toFile().getName()); // should print tExtFile.txt
Code above throws FsEntryNotFoundException ... (no such entry)
It works for regular java.io.File, not sure why not for TFile of TrueZip or I am missing something?
My goal is to access each file just using only lowercase for files and folders.
Edit: 24-03-2017
Let's say I would like to read bytes from file inside mentioned zip archive MyZip.zip
Path tPath = new TPath("...MyZip.zip\\myFolder\\tExtFile.txt");
byte[] bytes = Files.readAllBytes(tPath); //returns bytes of the file
This snippet above works, but this one below does not (throws mentioned -> FsEntryNotFoundException). It is the same path and file just in lowercase.
Path tPath = new TPath("...myzip.zip\\myfolder\\textfile.txt");
byte[] bytes = Files.readAllBytes(tPath);
You said:
My goal is to access each file just using only lowercase for files and folders.
But wishful thinking will not get you very far here. As a matter of fact, most file systems (except Windows types) are case-sensitive, i.e. in them it makes a big difference if you use upper- or lower-case characters. There you can even have the "same" file name in different case multiple times in the same directory. I.e. it actually makes a difference if the name is file.txt, File.txt or file.TXT. Windows is really an exception here, but TrueZIP does not emulate a Windows file system but a general archive file system which works for ZIP, TAR etc. on all platforms. Thus, you do not have a choice whether you use upper- or lower-case characters, but you have to use them exactly as stored in the ZIP archive.
Update: Just as a little proof, I logged into a remote Linux box with an extfs file system and did this:
~$ mkdir test
~$ cd test
~/test$ touch file.txt
~/test$ touch File.txt
~/test$ touch File.TXT
~/test$ ls -l
total 0
-rw-r--r-- 1 group user 0 Mar 25 00:14 File.TXT
-rw-r--r-- 1 group user 0 Mar 25 00:14 File.txt
-rw-r--r-- 1 group user 0 Mar 25 00:14 file.txt
As you can clearly see, there are three distinct files, not just one.
And what happens if you zip those three files into an archive?
~/test$ zip ../files.zip *
adding: File.TXT (stored 0%)
adding: File.txt (stored 0%)
adding: file.txt (stored 0%)
Three files added. But are they still distince files in the archive or just stored under one name?
~/test$ unzip -l ../files.zip
Archive: ../files.zip
Length Date Time Name
--------- ---------- ----- ----
0 2017-03-25 00:14 File.TXT
0 2017-03-25 00:14 File.txt
0 2017-03-25 00:14 file.txt
--------- -------
0 3 files
"3 files", it says - quod erat demonstrandum.
As you can see, Windows is not the whole world. But if you copy that archive to a Windows box and unzip it there, it will only write one file to a disk with NTFS or FAT file system - which one is a matter of luck. Very bad if the three files have different contents.
Update 2: Okay, there is no solution within TrueZIP for the reasons explained in detail above, but if you want to work around it, you can do it manually like this:
package de.scrum_master.app;
import de.schlichtherle.truezip.nio.file.TPath;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
public class Application {
public static void main(String[] args) throws IOException, URISyntaxException {
TPathHelper tPathHelper = new TPathHelper(
new TPath(
"../../../downloads/powershellarsenal-master.zip/" +
"PowerShellArsenal-master\\LIB/CAPSTONE\\LIB\\X64\\LIBCAPSTONE.DLL"
)
);
TPath caseSensitivePath = tPathHelper.getCaseSensitivePath();
System.out.printf("Original path: %s%n", tPathHelper.getOriginalPath());
System.out.printf("Case-sensitive path: %s%n", caseSensitivePath);
System.out.printf("File size: %,d bytes%n", Files.readAllBytes(caseSensitivePath).length);
}
}
package de.scrum_master.app;
import de.schlichtherle.truezip.file.TFile;
import de.schlichtherle.truezip.nio.file.TPath;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
public class TPathHelper {
private final TPath originalPath;
private TPath caseSensitivePath;
public TPathHelper(TPath tPath) {
originalPath = tPath;
}
public TPath getOriginalPath() {
return originalPath;
}
public TPath getCaseSensitivePath() throws IOException, URISyntaxException {
if (caseSensitivePath != null)
return caseSensitivePath;
final TPath absolutePath = new TPath(originalPath.toFile().getCanonicalPath());
TPath matchingPath = absolutePath.getRoot();
for (Path subPath : absolutePath) {
boolean matchFound = false;
for (TFile candidateFile : matchingPath.toFile().listFiles()) {
if (candidateFile.getName().equalsIgnoreCase(subPath.toString())) {
matchFound = true;
matchingPath = new TPath(matchingPath.toString(), candidateFile.getName());
break;
}
}
if (!matchFound)
throw new IOException("element '" + subPath + "' not found in '" + matchingPath + "'");
}
caseSensitivePath = matchingPath;
return caseSensitivePath;
}
}
Of course, this is a little ugly and will just get you the first matching path if there are multiple case-insensitive matches in an archive. The algorithm will stop searching after the first match in each subdirectory. I am not particularly proud of this solution, but it was a nice exercise and you seem to insist that you want to do it this way. I just hope you are never confronted with a UNIX-style ZIP archive created on a case-sensitive file system and containing multiple possible matches.
BTW, the console log for my sample file looks like this:
Original path: ..\..\..\downloads\powershellarsenal-master.zip\PowerShellArsenal-master\LIB\CAPSTONE\LIB\X64\LIBCAPSTONE.DLL
Case-sensitive path: C:\Users\Alexander\Downloads\PowerShellArsenal-master.zip\PowerShellArsenal-master\Lib\Capstone\lib\x64\libcapstone.dll
File size: 3.629.294 bytes
I dont have TrueZip installed but I was also wondering how it would work in normal Path, so I implemented below way quite similar #kriegaex solution, you can try using caseCheck(path):
public class Main {
/**
* #param args
* #throws Exception
*/
public static void main(String[] args) throws Exception {
Path path = Paths.get("/home/user/workspace/JParser/myfolder/yourfolder/Hisfolder/a.txt");
Instant start = Instant.now();
Path resolution;
try{
resolution = caseCheck(path);
}catch (Exception e) {
throw new IllegalArgumentException("Couldnt access given path", e);
}
Instant end = Instant.now();
Duration duration = Duration.between(start, end);
System.out.println("Path is: " + resolution + " process took " + duration.toMillis() + "ms");
}
/**
* #param path
* #return
* #throws IOException
*/
private static Path caseCheck(Path path) throws IOException {
Path entryPoint = path.isAbsolute() ? path.getRoot() : Paths.get(".");
AtomicInteger counter = new AtomicInteger(0);
while (counter.get() < path.getNameCount()) {
entryPoint = Files
.walk(entryPoint, 1)
.filter(s -> checkPath(s, path, counter.get()))
.findFirst()
.orElseThrow(()->new IllegalArgumentException("No folder found"));
counter.getAndIncrement();
}
return entryPoint;
}
/**
* #param s
* #param path
* #param index
* #return
*/
private static final boolean checkPath(Path s, Path path, int index){
if (s.getFileName() == null) {
return false;
}
return s.getFileName().toString().equalsIgnoreCase(path.getName(index).toString());
}
}
I want to determine if a new file or document is placed inside a specific folder/directory using java. For example, There are no files inside the "C:\Users\User\Documents" directory and then I downloaded a pdf file from the Internet and was placed on the mentioned directory. How can I determine if a new file is detected on the directory using java programming language? (It should also print-out the name of the directory and the new file name). Can I have any tips on how to create this kind of program using Java language? It should be continuous or in an infinite loop.
I tried this by using this:
package readfilesfromfolder;
import java.io.File;
public class ReadFilesFromFolder {
public static File folder = new File("C:/Documents and Settings/My Documents/Downloads");
static String temp = "";
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Reading files under the folder "+ folder.getAbsolutePath());
listFilesForFolder(folder);
}
public static void listFilesForFolder(final File folder) {
for (final File fileEntry : folder.listFiles()) {
if (fileEntry.isDirectory()) {
listFilesForFolder(fileEntry);
} else {
if (fileEntry.isFile()) {
temp = fileEntry.getName();
if ((temp.substring(temp.lastIndexOf('.') + 1, temp.length()).toLowerCase()).equals("txt"))
System.out.println("File= " + folder.getAbsolutePath()+ "\\" + fileEntry.getName());
}
}
}
}
}
But based on the outcome, it just accessed the directory but did not list for any new items. Also, it is not yet in loop because I haven't placed it yet. Thank you :) (*Note: I am still new to Java programming :) *)
You could use the Watch Service. A watch service that watches registered objects for changes and events. For example a file manager may use a watch service to monitor a directory for changes so that it can update its display of the list of files when files are created or deleted.
A good example can be found here.
You too can use the Commons IO library from the Apache Foundation, mainly the org.apache.commons.io.monitor package.
Thank you guys for the tip! :) I found out how to do this using the WatchService :)
This is the output based on my research and reading :)
public static void main(String[] args) throws IOException{
// TODO code application logic here
WatchService watchService = FileSystems.getDefault().newWatchService();
//The path needed for changes
Path directory = Paths.get("C:\\Users\\User\\Documents");
//To determine whether a file is created, deleted or modified
//ENTRY_CREATE can be changed to ENTRY_MODIFY and ENTRY_DELETE
WatchKey watchKey = directory.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
//This portion is for the output of what file is created, modified, or deleted
while (true){
for (WatchEvent<?> event : watchKey.pollEvents()) {
System.out.println(event.kind());
Path file = directory.resolve((Path) event.context());
System.out.println(file);
}
}
}
Hope this can help other people. Thanks also to those who helped me as well as to the authors of different research materials used to create this one :) Credits to Mr.Kriechel for this one :)
I have a JAVA program to display the contents of a folder: files, folders and the contents of the subfolders.
public static void displayContent(File curFolder, int indent){
if(curDir.isFile()){
System.out.println(curDir.getName());
} else if(curDir.isFolder()){
System.out.println(curDir.getName());
if(curDir.length() > 0){
for(File file: curDir.listFiles()){
displayContent(file, indent + 4);
}
}
}
}
I created a test folder with a bunch of subfolders to test my program and it runs very well. But when I use my program to test system folders such as "C:\Users", it returns a lot of unexpected results:
It displays some folders I cannot find in the folder, such as "All users", "Application Data". Plus they are not hidden files.
Some folders and files do exist, but they do not show in my results. The name of the folder containing these files begins with a dot, such as ".android". What is this type of folder? How do I deal with it?
My OS is windows 8; IDE is NetBeans 8.0.
I'm pretty sure you want to print the path instead of printing the name. That way you can see the folder structure. Also, your code seems to have a fairly large number of typos,
public static void displayContent(File curDir, int indent) { // <-- curDir used below
if (curDir.isFile()) {
System.out.println(curDir.getPath());
} else if (curDir.isDirectory()) {
System.out.println(curDir.getPath());
for (File file : curDir.listFiles()) {
displayContent(file, indent + 4); // <-- displayContent not displayContents.
}
}
}
I am currently working on a project for school, it is Java based and I am using Eclipse on Linux Mint to write it. The assignment says use the statement String[] filenames = new java.io.File("icons).list(); to create an array of file names.
The problem is I am not sure what to do with this, I have spent the past few hours searching the Internet and my textbook, but to no avail. Does it need to be a separate method?
Below is my guess for the needed code in the model (the project is to make a matching game, with a GUI) the names will have to be converted later on into actual icons, but I am pretty sure I have that part figured out, I just can't seem to get the darn files into the array!!
Thanks in advance,
public String[] list() {
String[] fileNames = new java.io.File("icons").list();
return fileNames;
}
In Java, the File class does not necessary represent an "existing" file on the file system. For example:
File f = new File("some_unknown_unexisting_file.bob");
System.out.println(f.exists()); // most likely will print 'false'
Also, the class resolves the file from the current working directory. You may get this directory with
System.out.println(new File(".").getAbsolutePath());
In your case, if you can, I would suggest getting a File[] array with :
File[] files = new File("icons").listFiles(new FileFilter() {
#Override
public boolean accept(File f) {
return !f.isDirectory() && f.canRead();
}
});
for (File f : files) {
System.out.println(f.getAbsolutePath());
}
which will return an array of File objects which are not folders and that you can open for reading (note that this is not always true, but is just fine in your case).
But if you have to use list(), then this is equivalent :
File parent = new File("icons");
String[] fileStr = parent.list(new FilenameFilter() {
#Override
public boolean accept(File dir, String name) {
File f = new File(dir, name);
return !f.isDirectory() && f.canRead();
}
});
for (String f : fileStr) {
System.out.println(new File(parent, f).getAbsolutePath());
}
Also, with your list of files (String[]), you can create an icon using :
String filename = fileStr[i]; // some file name within the array
ImageIcon icon = new ImageIcon("icons" + File.separator + filename);
or with your list of files (File[]), it is cleaner :
File file = files[i]; // some file within the File[] array
ImageIcon icon = new ImageIcon(file.getAbsolutePath());
Good luck.
The code you wrote looks okay. Are you sure the folder "icons" exists where Java is looking?
Try this:
File f = new File("icons");
System.out.println("Does icons exist?" + f.exists());
System.out.println("Is it a dir?" + f.isDirectory());
System.out.println("How many files does it contain?" + f.list().length);
Good luck!
I've had the same problem. When I tried moving the icons folder into the folder just before the src folder, it seems to work. Not sure what I will do when I submit the assignment, as for it to work in JCreator, I believe it has to be with the .java files.