This question already has answers here:
Monitor subfolders with a Java watch service
(3 answers)
Closed 6 years ago.
My program is monitoring any file change in specified file path, if there's any new file coming, it will raise a notification, But going to fail when there's any sub folder created in parent folder. The file path for parent folder is being monitor C:/play but when there is a new sub folder created like C:/play/abcinside the parent folder, my program able to detect, but when i am trying to insert any file into abc folder, my program is not able to detect that new file has been created. I have tested various methods but unfortunately i can't let it work.Anyone able to provide me any guide on my reference link?My sample code is following the guide in my reference link
This is my source code after adding into the function for checking sub directory
public class fileStatus
{
public static void main(String [] args) throws InterruptedException
{
try(WatchService svc = FileSystems.getDefault().newWatchService())
{
Map<WatchKey, Path> keyMap = new HashMap<>();
Path path = Paths.get("C:/play");
fileStatus fd = new fileStatus();
fd.registerAll(path);
keyMap.put(path.register(svc,
StandardWatchEventKinds.ENTRY_CREATE),
path);
WatchKey wk ;
do
{
wk = svc.take();
Path dir = keyMap.get(wk);
for(WatchEvent<?> event : wk.pollEvents())
{
WatchEvent.Kind<?> type = event.kind();
Path fileName = (Path)event.context();
System.out.println("\nThe new file :"+fileName+ "Event :" +type); //print the new file name
}
}while(wk.reset());
}
catch(IOException e)
{
System.out.println("Problem io in somewhere");
}
}
private void registerAll(Path path) throws IOException
{
Files.walkFileTree(path, new SimpleFileVisitor<Path>()
{
#SuppressWarnings("unused")
public FileVisitResult preVisitDireotry(Path path,BasicFileAttributes attrs) throws IOException
{
return FileVisitResult.CONTINUE;
}
});
}
}
This is my reference code and my folder structure look like this,
/root
/Folder A
/test.txt
/Folder B
/abc.txt
In short, you have only registered the parent directory to be watched. Any sub-directories you create will not be watched. See here.
Related
I am trying to filter hidden files using the NIO classes.
When I run the attached code on Windows 10 I get the following output:
Files:
c:\Documents and Settings
c:\PerfLogs
c:\Program Files
c:\Program Files (x86)
c:\Users
c:\Windows
Paths:
c:\$Recycle.Bin
c:\Config.Msi
c:\Documents and Settings
c:\Intel
c:\IntelOptaneData
c:\OEM
c:\OneDriveTemp
c:\PerfLogs
c:\Program Files
c:\Program Files (x86)
c:\ProgramData
c:\Recovery
c:\System Volume Information
c:\Users
c:\Windows
The list displayed under Files (using the old File.listFiles(FileFilter) method) is the list I see in Windows File Explorer and is what I am expecting to see (except for the Document and Setting and I know how to fix that)
Why is the NIO approach not filtering hidden files the same way?
How do I get NIO filtering to be the same?
Here is the test code:
import java.io.*;
import java.nio.file.*;
public class ListFilesNIO
{
public static void main(String[] args) throws Exception
{
String directory = "c:\\";
// Use old File I/O
FileFilter fileFilter = new FileFilter()
{
#Override
public boolean accept(File entry)
{
if (entry.isHidden()) return false;
return true;
}
};
System.out.println("Files:");
File[] files = new File( directory ).listFiles( fileFilter );
for (File file : files)
{
System.out.println( "\t" + file );
}
// Use NIO
DirectoryStream.Filter<Path> pathFilter = new DirectoryStream.Filter<Path>()
{
#Override
public boolean accept(Path entry) throws IOException
{
if (Files.isHidden( entry )) return false;
return true;
}
};
System.out.println();
System.out.println("Paths:");
DirectoryStream<Path> paths = Files.newDirectoryStream(Paths.get( directory ), pathFilter);
for (Path path : paths)
{
System.out.println( "\t" + path );
}
}
}
Note: when I run the code without the filter, in both cases 18 files are displayed. So the first approach is filtering 12 hidden files and the second approach is only filtering 3 files.
It's not a bug but a feature(!) known since jdk7, Windows hidden directory are not detected as hidden, see this bug and this one (fix jdk13).
As a workaround, you can do this :
import java.nio.file.attribute.DosFileAttributes;
...
DirectoryStream.Filter<Path> pathFilter = new DirectoryStream.Filter<Path>()
{
#Override
public boolean accept(Path entry) throws IOException
{
DosFileAttributes attr = Files.readAttributes(entry, DosFileAttributes.class);
return !attr.isHidden();
}
};
I ended up using:
DirectoryStream.Filter<Path> pathFilter = new DirectoryStream.Filter<Path>()
{
#Override
public boolean accept(Path entry) throws IOException
{
DosFileAttributes attr = Files.readAttributes(entry, DosFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
return !attr.isHidden();
}
};
As I mentioned in my question, I also want the Documents and Settings to be hidden.
The Documents and Settings is a link to C:\Users.
The default implementation for the Files.readAttributes(…) method is to follow links. So I guess because the c:\Users directory is not hidden, the Documents and Settings is also considered not hidden.
By using LinkOption.NOFOLLOW_LINKS it is considered hidden, which is what I want.
I downloaded a text file by a click button functionality, using Selenium Java.
then the file is downloaded to a particular location in the system, for example,
C://myAppfiles.
But I can't access that downloaded folder because of some reason. But I have to read that file while downloading.
How to do it? is it possible to read that file from the browser(chrome) using selenium or any other method is available?
so I'd suggest to do the following:
wait until file download is done completely.
After that- try to list all the files in the given directory:
all files inside folder and sub-folder
public static void main(String[]args)
{
File curDir = new File(".");
getAllFiles(curDir);
}
private static void getAllFiles(File curDir) {
File[] filesList = curDir.listFiles();
for(File f : filesList){
if(f.isDirectory())
getAllFiles(f);
if(f.isFile()){
System.out.println(f.getName());
}
}
}
files/folder only
public static void main(String[]args)
{
File curDir = new File(".");
getAllFiles(curDir);
}
private static void getAllFiles(File curDir) {
File[] filesList = curDir.listFiles();
for(File f : filesList){
if(f.isDirectory())
System.out.println(f.getName());
if(f.isFile()){
System.out.println(f.getName());
}
}
}
That will help You to understand if there any files at all (in the given directory).
Dont forget to make paths platform independent (to the folder/ file), like:
//platform independent and safe to use across Unix and Windows
File fileSafe = new File("tmp"+File.separator+"myDownloadedFile.txt");
Also, You might want to check whether file actually exists via Path methods.
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) throws Exception {
Path filePath= Paths.get("C:\\myAppfiles\\downloaded.txt");
System.out.println("if exists: " + Files.exists(firstPath));
}
}
Additionally, path suggests You to check some other options on the file:
The following code snippet verifies that a particular file exists and that the program has the ability to execute the file.
Path file = ...;
boolean isRegularExecutableFile = Files.isRegularFile(file) &
Files.isReadable(file) & Files.isExecutable(file);
Once You face any exception- feel free to post it here.
Hope this helps You
How to rename folder even if the target folder with same name has already existed in the directory.
I have tried the method renameTo of class File,but it does not work.
For example:
/root
/a
/b
I want to rename folder b with the name of folder a, actually the folder a will be replaced,yes,that's what I want.
You need to first delete everything in 'a' or move/rename it to something else.
You can delete it with Apache's recurrsive deleteDictionary function. This gets every file in the aFolder and deletes it, then deletes the folder itself.
FileUtils.deleteDirectory(aFolder);
Then, you can use #renameTo
bFolder.renameTo(aFolder);
In Java 7 and above you can turn to Files for delete and move.
In your case, you can achieve it as follows:
public class HelloWord {
public static void main(String... args) throws Exception {
Path targetPath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/resources/").concat("a"));
Path thePath = Paths.get(Paths.get("").toAbsolutePath().toString().concat("/src/resources/").concat("b"));
if (Files.exists(targetPath)) { // if the target folder exists, delete it first;
deleteFolder(targetPath);
}
Files.move(thePath, targetPath);
}
private static void deleteFolder(Path path) {
try {
if (Files.isRegularFile(path)) { // delete regular file directly;
Files.delete(path);
return ;
}
try (Stream<Path> paths = Files.walk(path)) {
paths.filter(p -> p.compareTo(path) != 0).forEach(p -> deleteFolder(p)); // delete all the children folders or files;
Files.delete(path); // delete the folder itself;
}
} catch (IOException ignored) {
ignored.printStackTrace();
}
}
}
My local test
The structure of the folder for my local test is as follows:
The result:
The solution uses java.nio.file.Files class's move static method.
import java.nio.file.*;
import java.io.IOException;
import java.nio.file.attribute.*;
import java.util.*;
import java.util.stream.*;
public class FilesMoveExample {
public static void main (String [] args)
throws IOException {
Path srcePath = Paths.get("C:\\java-nio2\\folder1");
Path targetPath = Paths.get("C:\\java-nio2\\folder2");
Files.move(srcePath, targetPath); // NOTE: Statement A
}
}
Assume folder1 is source directory and contains multiple sub-directories and files.
Scenario 1:
'Statement A' used as it is.
Source folder1 exists and the target folder2 does not exist.
On running the code, folder1 is renamed to folder2. The folder1's file tree is moved to folder2.
Scenario 2:
'Statement A' modified to: Files.move(srcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
Source folder1 and the target folder2 (an empty directory) exists.
On running the code, the target folder2 is replaced with folder1 (and renamed to folder2). The folder1's file tree is moved to folder2.
Scenario 3:
'Statement A' modified to: Files.move(srcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
Source folder1 and the target folder2 (a non-empty directory) exists.
On running the code, throws DirectoryNotEmptyException.
In this scenario 3 the target directory needs to be empty for the move to complete successfully. So, delete the target directory recursively using one of the following methods, and perform the move. The first uses Java 7 and the next uses Java 8:
private static void deleteUsingWalkFileTree(Path start)
throws IOException {
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult postVisitDirectory(Path dir, IOException e)
throws IOException {
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
} else {
throw e;
}
}
});
}
private static void deleteUsingWalk(Path start )
throws IOException {
List<Path> files = Files.walk(start)
.sorted(Comparator.reverseOrder())
.collect(Collectors.toList());
for (Path p : files) {
Files.delete(p);
}
}
I'm using the following code to capture events in a given folder. It works fine, but my question is how can I capture events in sub folders in my given folder as well?
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationListenerAdaptor;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
public class Monitor {
public Monitor() {
}
//path to a folder you are monitoring .
public static final String FOLDER = MYPATH;
public static void main(String[] args) throws Exception {
System.out.println("monitoring started");
// The monitor will perform polling on the folder every 5 seconds
final long pollingInterval = 5 * 1000;
File folder = new File(FOLDER);
if (!folder.exists()) {
// Test to see if monitored folder exists
throw new RuntimeException("Directory not found: " + FOLDER);
}
FileAlterationObserver observer = new FileAlterationObserver(folder);
FileAlterationMonitor monitor =
new FileAlterationMonitor(pollingInterval);
FileAlterationListener listener = new FileAlterationListenerAdaptor() {
// Is triggered when a file is created in the monitored folder
#Override
public void onFileCreate(File file) {
// "file" is the reference to the newly created file
System.out.println("File created: "+ file.getCanonicalPath());
}
// Is triggered when a file is deleted from the monitored folder
#Override
public void onFileDelete(File file) {
try {
// "file" is the reference to the removed file
System.out.println("File removed: "+ file.getCanonicalPath());
// "file" does not exists anymore in the location
System.out.println("File still exists in location: "+ file.exists());
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
};
observer.addListener(listener);
monitor.addObserver(observer);
monitor.start();
}
}
I've read here enter link description here that this code is suppose to capture events in sub folders as well, but I does not work.
The statement you make regarding the hyperlink after your code is not accurate. The code in Capture events happening inside a directory DOES capture certain events (file create, file delete) in the main/root directory and subfolders. It does not monitor file modification or folder operations (create, delete, rename, etc.).
I have just tested it on 3 levels down (nested subfolders). As such the code you are referring to accomplishes what you are asking for. If you need something different please re-phrase/re-word your question.
If you need more information on the subject you might find this link: https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/monitor/FileAlterationListenerAdaptor.html useful. It definitely helped me.
When I run a class with the following code:
public static void main(String[] args)
{
createDuplicateStructure("in", "out");
}
public static void createDuplicateStructure(String path_start, String path_result)
{
File start = new File(path_start);
File result = new File(path_result);
duplicateDirectoryStructure(start, result);
}
public static void duplicateDirectoryStructure(File start_dir, File result_dir)
{
//FileFilter used by listFiles(filter) - to make sure they are dirs
FileFilter dirs_only = new FileFilter()
{
public boolean accept(File file){ return file.isDirectory();}
};
File[] dir_contents = start_dir.listFiles(dirs_only);
for(File dir : dir_contents)
{
File duplicate = new File(result_dir.getPath(), dir.getName());
if(dir.mkdir())
{
duplicateDirectoryStructure(dir, duplicate);
}
else
{
System.out.println("ERROR: Unable to create dir! (" + duplicate.getPath() + ")");
}
}
}
I get this in the console:
Error: Unable to create dir! (out/a)
Error: Unable to create dir! (out/a)
Error: Unable to create dir! (out/a)
The directory "out" is in the same directory as the .jar.
There is a directory "in" which contains "a", "b", and "c" directories (for testing).
Any ideas why this is not working?
Thanks!
You should replace dir.mkdir() with duplicate.mkdir() because dir is the already existing source directory.
dir.mkdir() only returns true the directory was actually created. Try doing
if(dir.mkdir() || dir.exists())
The line
`if(dir.mkdir())`
is trying to create the existing directory structure
if you change it to
if(duplicate.mkdir())
you get another problem where it tries to create the a subdirectory under out which does not exist yet.
So change it to
if(duplicate.mkdirs())
which will create the directory structure, or create the out directory before you start your loop.