I'm trying to implement a recursive directory watching functionality. But I found the API very hard to understand.
Let's say I have an empty directory which is the root of the directory tree I would like to watch. Now I create a new directory within this root (it's default name is 'New folder' in Windows 7) and I immediately rename it to something like 'xxx'.
The problem is when I copy a file in the new created 'xxx' directory. The WatchEvent's context is 'New folder' instead of the 'xxx'.
Here is my sscce:
public class Test {
private static final String SRC_DIR = "D:/test";
private final WatchService watcherService;
public Test() throws IOException {
watcherService = FileSystems.getDefault().newWatchService();
registerDirectoryTree(Paths.get(SRC_DIR));
startWatching();
}
private void startWatching() throws IOException {
while (true) {
WatchKey watchKey;
try {
watchKey = watcherService.take();
} catch (InterruptedException e) {
break;
}
Path directory = null;
try {
directory = (Path) watchKey.watchable();
for (WatchEvent<?> event : watchKey.pollEvents()) {
if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
Path fileName = (Path) event.context();
Path filePath = directory.resolve(fileName);
if (Files.isDirectory(filePath, LinkOption.NOFOLLOW_LINKS)) {
registerDirectoryTree(filePath);
} else if (Files.isRegularFile(filePath, LinkOption.NOFOLLOW_LINKS)) {
System.out.println("Processing file. Path: " + filePath);
} else {
System.out.println("Unknown path type. Path: " + filePath);
}
}
}
} finally {
boolean valid = watchKey.reset();
if (!valid) {
System.out.println("Watch key is not valid. Directory: " + directory);
}
}
}
}
private void registerDirectoryTree(Path sourceDir) throws IOException {
Files.walkFileTree(sourceDir, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
registerDirectory(dir);
return FileVisitResult.CONTINUE;
}
});
}
private void registerDirectory(Path path) throws IOException {
System.out.println("Registering watch service on " + path);
path.register(watcherService, StandardWatchEventKinds.ENTRY_CREATE);
}
public static void main(String[] args) throws IOException {
new Test();
}
}
Related
I am working on an application which will download 3rd party dependencies to a particular folder and then execute dependency check on it. The files downloaded can be of any type, they can be zip, jar or may b a folder. I am trying to find a code example but nothing seems to work for me. I tried NIO in java but that seems to work only for writing to a particular file not folder. Below is code where I used NIO
// Checking If The File Exists At The Specified Location Or Not
Path filePathObj = Paths.get(filePath);
boolean fileExists = Files.exists(filePathObj);
if(fileExists) {
try {
urlObj = new URL(sampleUrl);
rbcObj = Channels.newChannel(urlObj.openStream());
fOutStream = new FileOutputStream(filePath);
fOutStream.getChannel().transferFrom(rbcObj, 0, Long.MAX_VALUE);
System.out.println("! File Successfully Downloaded From The Url !");
} catch (IOException ioExObj) {
System.out.println("Problem Occured While Downloading The File= " + ioExObj.getMessage());
} finally {
try {
if(fOutStream != null){
fOutStream.close();
}
if(rbcObj != null) {
rbcObj.close();
}
} catch (IOException ioExObj) {
System.out.println("Problem Occured While Closing The Object= " + ioExObj.getMessage());
}
}
} else {
System.out.println("File Not Present! Please Check!");
}```
public Class CopyAndWrite {
public static final String SOURCES = "C:\\Users\\Administrator\\Desktop\\resources";
public static final String TARGET = "C:\\Users\\Administrator\\Desktop\\111";
public static void main (String[]args) throws IOException {
Path startingDir = Paths.get(SOURCES);
Files.walkFileTree(startingDir, new FindJavaVisitor());
}
private static class FindJavaVisitor extends SimpleFileVisitor<Path> {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
if (!StringUtils.equals(dir.toString(), SOURCES)) {
Path targetPath = Paths.get(TARGET + dir.toString().substring(SOURCES.length()));
if (!Files.exists(targetPath)) {
Files.createDirectory(targetPath);
}
}
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path targetPath = Paths.get(TARGET + file.toString().substring(SOURCES.length()));
copyFile(targetPath, Files.readAllBytes(file));
return FileVisitResult.CONTINUE;
}
}
private static void copyFile (Path path,byte[] bytes){
// write file
try {
Files.write(path, bytes);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Using OKHttpClient to download the file and place in a folder.
Request request = new Request.Builder().url(downloadUrl).build();
Response response;
try {
response = client.newCall(request).execute();
if (response.isSuccessful()) {
fileName = abc.zip
Path targetPath = new File(inDir + File.separator + fileName).toPath();
try (FileOutputStream fos = new FileOutputStream(targetPath)) {
fos.write(response.body().bytes());
}
return 0;
}
} catch (IOException e) {
logger.error(e.getMessage());
}```
I have been trying to watch folders through UNC. There are a lot of folders in the main folder. When I run the watch service it is registering all the folders with watch service. After all these folders are registered the watch service receives the events with Invalid key i-e key.isValid() returns false. And at this moment the particular folder is excluded from watch. I have reset the key but it is also giving me false. In short I am unable to watch for those folders which are excluded from key. I even tried to re register the folders but that again generates the invalid key and cannot be watched. I have tried this with normal folders in the same machine. They are working fine. Please help me if I am missing something. If I limit the folders to around 50-60 watch service doesn't receive any invalid key event and everything is working fine.
This is the code that will create number of folders.
import java.io.File;
public class CreateDir {
public static void main(String args[]){
for(int j=0; j<1000; j++){
String folderName = "Folder"+j;
new File("\\\\Server2\\Shared Folder\\test\\" + folderName + "\\" + folderName + "_Folder1" + "\\" + folderName + "_Folder2" + "\\"
+ folderName + "_Folder3" + "\\" + folderName + "_Folder4" + "\\" + folderName + "_Folder5"+"\\"
+ folderName + "_Folder6" + "\\" + folderName + "_Folder7" + "\\" + folderName + "_Folder8" + "\\"
+ folderName + "_Folder9" + "\\" + folderName + "_Folder10").mkdirs();
}
}
}
This is the class that is actually watching these UNC Paths and giving information regarding events.
import java.nio.file.*;
import static java.nio.file.StandardWatchEventKinds.*;
import static java.nio.file.LinkOption.*;
import java.nio.file.attribute.*;
import java.io.*;
import java.util.*;
public class WatchDir {
private final WatchService watcher;
private final Map<WatchKey,Path> keys;
private final boolean recursive;
private boolean trace = false;
private int total = 0;
#SuppressWarnings("unchecked")
static <T> WatchEvent<T> cast(WatchEvent<?> event) {
return (WatchEvent<T>)event;
}
/**
* Register the given directory with the WatchService
*/
private void register(Path dir, PrintWriter writer) throws IOException {
WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
if (trace) {
Path prev = keys.get(key);
if (prev == null) {
writer.println("register:"+dir);
} else {
if (!dir.equals(prev)) {
writer.println("update.........");
}
}
}
keys.put(key, dir);
}
/**
* Register the given directory, and all its sub-directories, with the
* WatchService.
*/
private void registerAll(final Path start, PrintWriter writer){
// register directory and sub-directories
try{
Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
{
writer.println(++total+"Registering Path...."+dir.toUri());
try{
register(dir,writer);
}catch(IOException ex){
writer.println("Error occurred for Path..."+dir.getFileName());
}catch(Exception ex){
System.out.println("error");
}
return FileVisitResult.CONTINUE;
}
});
}catch(Exception ex){
writer.println("Not Registered ....."+ex.getMessage());
}
}
/**
* Creates a WatchService and registers the given directory
*/
WatchDir(Path dir, boolean recursive, PrintWriter writer) throws IOException {
this.watcher = FileSystems.getDefault().newWatchService();
this.keys = new HashMap<WatchKey,Path>();
this.recursive = recursive;
if (recursive) {
System.out.println("Starting Registering Path");
writer.println("Scanning %s ...\n"+ dir);
registerAll(dir, writer);
writer.println("Done.");
System.out.println("Done");
writer.println("Total Folders in Watch "+ total);
System.out.println("Total Folders in Watch "+ total);
} else {
register(dir,writer);
}
// enable trace after initial registration
this.trace = true;
}
/**
* Process all events for keys queued to the watcher
* #throws UnsupportedEncodingException
* #throws FileNotFoundException
*/
void processEvents() throws FileNotFoundException, UnsupportedEncodingException {
PrintWriter writer1 = new PrintWriter("C:\\test\\key.txt");
for (;;) {
// wait for key to be signalled
WatchKey key;
try {
key = watcher.take();
writer1.println("Folder is "+key.watchable()+" And Key is "+ key.isValid());
System.out.println("Folder is "+key.watchable()+" And Key is "+ key.isValid());
} catch (InterruptedException x) {
writer1.println("Interupped Exception.........");
return;
}
Path dir = keys.get(key);
if (dir == null) {
writer1.println("WatchKey not recognized!!");
continue;
}
for (WatchEvent<?> event: key.pollEvents()) {
WatchEvent.Kind kind = event.kind();
// TBD - provide example of how OVERFLOW event is handled
if (kind == OVERFLOW) {
writer1.println("Overflow event is caught.");
continue;
}
// Context for directory entry event is the file name of entry
WatchEvent<Path> ev = cast(event);
Path name = ev.context();
Path child = dir.resolve(name);
// print out event
System.out.format("%s: %s\n", event.kind().name(), child);
writer1.println("Event Kind is "+event.kind().name() +" And Name is "+child);
// if directory is created, and watching recursively, then
// register it and its sub-directories
if (recursive && (kind == ENTRY_CREATE)) {
try {
if (Files.isDirectory(child, NOFOLLOW_LINKS)) {
registerAll(child, writer1);
}
} catch (Exception x) {
// ignore to keep sample readbale
}
}
}
// reset key and remove from set if directory no longer accessible
boolean valid = key.reset();
if (!valid) {
keys.remove(key);
// all directories are inaccessible
if (keys.isEmpty()) {
break;
}
}
}
}
static void usage() {
System.err.println("usage: java WatchDir [-r] dir");
System.exit(-1);
}
public static void main(String[] args) throws IOException {
// register directory and process its events
PrintWriter writer = new PrintWriter("C:\\test\\watch.txt");
Path dir = Paths.get("\\\\Server1\\Shared Folder\\test");
new WatchDir(dir, true,writer).processEvents();
}
}
I have tried this with JDK8 and JDK 11 both are giving the same issue.
Can somebody help me. I am new in Java and i want to copy file from one directory to another with CompletableFuture or ListenableFuture, but i dont know how to do this.
public void trackFiles(File source) {
if (source.exists()) {
File[] files = source.listFiles();
for (File file : files) {
if (file.isDirectory()) {
trackFiles(file);
} else {
allFile.add(file);
}
}
} else {
System.out.println("No such files!");
}
}
public void copyAllFilesRecursive(File source, File destination, CopyOption... options) {
if (source.isDirectory()) {
if (!destination.exists()) {
destination.mkdirs();
}
}
File[] contents = source.listFiles();
if (contents != null) {
ArrayList<File> listContents = new ArrayList<>(Arrays.asList(contents));
listContents.forEach(file -> {
File newFile = new File(destination.getAbsolutePath() + File.separator + file.getName());
if (file.isDirectory() && file.exists()) {
copyAllFilesRecursive(file, newFile, options);
} else {
try {
copyFiles(file, newFile, options);
} catch (IOException e) {
System.out.println(file + " exists");
}
}
});
}
}
There is no point in trying to make this operation asynchronous.
If you want a more readable code, you should use NIO, e.g.
public static void copyTree(Path from, Path to, CopyOption... options) throws IOException {
if(!Files.exists(to)) Files.createDirectories(to);
Files.walkFileTree(from, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
return !dir.equals(from)? copy(dir): FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
return copy(file);
}
private FileVisitResult copy(Path file) throws IOException {
Files.copy(file, to.resolve(from.relativize(file)), options);
return FileVisitResult.CONTINUE;
}
});
}
This will copy the content of from to to, e.g. when copying foo/bar to baz, it will copy everything within foo\bar to baz. If instead, you want the from directory copied, e.g. baz\bar created and everything within foo\bar copied to baz\bar, use
public static void copyTree(Path from, Path to, CopyOption... options) throws IOException {
from = from.toAbsolutePath();
Path base = from.getParent();
if(!Files.exists(to)) Files.createDirectories(to);
Files.walkFileTree(from, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
throws IOException {
return copy(dir);
}
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
return copy(file);
}
private FileVisitResult copy(Path file) throws IOException {
Files.copy(file, to.resolve(base.relativize(file)), options);
return FileVisitResult.CONTINUE;
}
});
}
If you really need the shown front-end method, it’s now as simple as
public static void copyAllFilesRecursive(File source, File destination,
CopyOption... options) throws IOException {
copyTree(source.toPath(), destination.toPath());
}
though it is very strange to combine the NIO CopyOption type with the legacy IO File type in one method…
Is there any faster method to find a folder that has no other folders inside?
File dir = new File("C:\\Users\\axs0552\\Desktop\\barcode\\");
File[] cartella = dir.listFiles();
List<String> Nome_cartela = null;
if (cartella == null) {
logger.debug("ERRORE: cartella inesistente, oppure directoy errata !!");
} else {
for (int i = 0; i < cartella.length; i++) {
if (cartella[i].isDirectory()) {
System.out.println("cartella radice n° :" + i + " " + cartella[i].getName());
File[] figli = cartella[i].listFiles();
for (int j = 0; i < figli.length; i++) {
if (figli[i].isDirectory()) {
System.out.println("cartella figlio n° :" + j + " " + figli[i].getName());
}
}
}
}
}
If you want to recursively examine all directories I suggest using a FileVisitor. This is a simple example that just outputs all names on entering and leaving and counts the directories:
public class MyFileVisitor implements FileVisitor<Path> {
private int dirCount = 0;
#Override
public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes bfa) throws IOException {
System.out.println("Entering directory: " + path);
dirCount++;
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult postVisitDirectory(Path path, IOException ex) throws IOException {
System.out.println("Leaving directory: " + path);
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(Path path, BasicFileAttributes bfa) throws IOException {
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFileFailed(Path path, IOException ex) throws IOException {
return FileVisitResult.CONTINUE;
}
public int getDirCount() {
return dirCount;
}
}
main could look like this:
public class Main {
public static void main(String[] args) {
Path path = Paths.get("c:/users");
MyFileVisitor fileVisitor = new MyFileVisitor();
try {
Files.walkFileTree(path, fileVisitor);
System.out.println(fileVisitor.getDirCount() + " directories");
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
If you only want to have the logic from your script you could write it like this (note that findFolderWihtoutSubfolders is static only for simplicity of main):
package tests;
import java.io.File;
public class Directories {
public static File findFolderWithoutSubfolders(File dir) {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
boolean flag = true;
for (File ff : f.listFiles()) {
if (ff.isDirectory()) {
flag = false;
break;
}
}
if (flag) {
return f;
}
}
}
return null;
}
public static void main(String[] args) {
File f = findFolderWithoutSubfolders(new File("C:\\Users\\stack\\test"));
if (f != null) {
System.out.println("Folder is : " + f.getName());
} else {
System.out.println("no folder found");
}
}
}
The simple way to print all empty directories below a root directory could be the below snippet.
assuming the follwing structure (file are named *.file)
/tmp/foo
/tmp/foo/bar
/tmp/foo/bar/bar.file
/tmp/foo/bar/barfoo
/tmp/foo/bar/foobar
/tmp/foo/bar/foobar/foobar.file
/tmp/foo/bar.file
/tmp/foo/baz
The snippet
Path rootPath = Paths.get("/tmp/foo");
Files.walk(rootPath, FileVisitOption.FOLLOW_LINKS)
.map(Path::toFile)
.filter((file) -> file.isDirectory() && file.listFiles().length == 0)
.forEach(System.out::println);
output
/tmp/foo/bar/barfoo
/tmp/foo/baz
the following directories are not printed
/tmp/foo/bar - contains subdirectories and a file
/tmp/foo/bar - contains a file
the method is not recursive. only two levels are checked. tree browsing is achieved using the file tree walking from nio2
import java.io.File;
import java.io.FileFilter;
// yet another file util class
public class YAFU {
public static void main(String[] args) {
File[] simpleFolders = YAFU.simpleFolders(new File("/tmp"));
if (simpleFolders == null)
System.out.println("nothing found");
else
for (File f : simpleFolders) {
System.out.println(f.getName());
}
}
public static boolean containsDirectories(File file) {
if (file == null || !file.isDirectory()) {
return false;
} else {
File[] found = file.listFiles(new FileFilter() {
#Override
public boolean accept(File file) {
return file.isDirectory();
}
});
return (found == null) ? false : found.length > 0;
}
}
public static File[] simpleFolders(File rootDir) {
if (rootDir == null || !rootDir.isDirectory()) {
return null;
} else {
return rootDir.listFiles(new FileFilter() {
#Override
public boolean accept(File file) {
return containsDirectories(file);
}
});
}
}
}
you can do following
public class LastFolderFinder {
public static void main(final String[] args){
final Path dir = Paths.get("C:\\Users\\axs0552\\Desktop\\barcode\\");
visitDir(dir);
}
private static void visitDir(final Path dir) {
try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dir, new DirectoryFilter());) {
final Iterator<Path> iterator = directoryStream.iterator();
if (iterator.hasNext()) {
while (iterator.hasNext()) {
final Path next = iterator.next();
visitDir(next);
}
} else {
System.out.println("last directory: " + dir);
}
} catch (final Exception exception) {
exception.printStackTrace();
}
}
}
class DirectoryFilter implements Filter<Path> {
#Override
public boolean accept(final Path entry) throws IOException {
return entry.toFile().isDirectory();
}
}
or you can do following updated https://stackoverflow.com/a/36084399/3333885 a little
public class LastFolderFinder {
public static void main(final String[] args) throws IOException {
final Path dir = Paths.get("C:\\Users\\axs0552\\Desktop\\barcode\\");
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
#Override
public FileVisitResult preVisitDirectory(final Path path, final BasicFileAttributes bfa) throws IOException {
if (hasDirectories(path)) {
return FileVisitResult.CONTINUE;
}
System.err.println(path);
return FileVisitResult.SKIP_SUBTREE;
}
#Override
public FileVisitResult postVisitDirectory(final Path path, final IOException ex) throws IOException {
return FileVisitResult.CONTINUE;
}
#Override
public FileVisitResult visitFile(final Path path, final BasicFileAttributes bfa) throws IOException {
return FileVisitResult.CONTINUE;
}
});
}
private static boolean hasDirectories(final Path dir) {
try (final DirectoryStream<Path> directoryStream = Files.newDirectoryStream(dir, new DirectoryFilter());) {
final Iterator<Path> iterator = directoryStream.iterator();
return iterator.hasNext();
} catch (final Exception exception) {
exception.printStackTrace();
}
return false;
}
}
class DirectoryFilter implements Filter<Path> {
#Override
public boolean accept(final Path entry) throws IOException {
return entry.toFile().isDirectory();
}
}
i code a program that searches for files in hard disk successfully. but now i want to add one more capability to it. i want that my program will upload these searched file on to a server through http. so can anyone explain what will be the strategy for this?
Here is my little program
public class Find {
public static class Finder extends SimpleFileVisitor<Path> {
private final PathMatcher matcher;
private int numMatches = 0;
Finder(String pattern)
{
matcher = FileSystems.getDefault().getPathMatcher("glob:" + pattern);
}
// Compares the glob pattern against
// the file or directory name.
void find(Path file)
{
Path name = file.getFileName();
if (name != null && matcher.matches(name))
{
numMatches++;
System.out.println(file);
}
}
// Prints the total number of
// matches to standard out.
void done()
{
System.out.println("Matched: "
+ numMatches);
}
// Invoke the pattern matching
// method on each file.
//#Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs)
{
find(file);
return CONTINUE;
}
// Invoke the pattern matching
// method on each directory.
//#Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs)
{
find(dir);
return CONTINUE;
}
//#Override
public FileVisitResult visitFileFailed(Path file,IOException exc)
{
System.err.println(exc);
return CONTINUE;
}
}
static void usage()
{
System.err.println("java Find <path>" +" -name \"<glob_pattern>\"");
System.exit(-1);
}
public static void main(String[] args)throws IOException
{
if (args.length < 1 )
{
usage();
}
Iterable<Path> root;
root = FileSystems.getDefault().getRootDirectories();
for (Path startingDir : FileSystems.getDefault().getRootDirectories())
{
String pattern = args[0];
Finder finder = new Finder(pattern);
Files.walkFileTree(startingDir, finder);
//finder.done();
}
}
}
OK, so assuming you've got an absolute filename of the File.
Just a rough idea of what should be done (not tested):
FileInputStream fileInputStream = null;
try {
new FileInputStream("absoluteFilename");
byte[] buffer = new byte[MAX_SIZE];
int bufferIndex = 0;
while (fileInputStream.available() > 0) {
buffer[bufferIndex++] = (byte) fileInputStream.read();
}
byte[] fileContent = new byte[bufferIndex];
System.arraycopy(buffer,0,fileContent,0,bufferIndex);
URL serverUrl = new URL(url);
URLConnection connection = serverURL.openConnection();
connection.setConnectTimeout(60000);
connection.getOutputStream().write(fileContent);
} catch (Exception fatal) {
//proper handling??
} finally {
if (fileInputStream != null) {
try {
fileInputStream.close();
} catch (Exception ignored) {}
}
}