I want to compare all file names from a given directory
Input/Output code:
static Scanner sc = new Scanner(System.in);
static String Directory = sc.next();
static File folder = new File(Directory);
static File[]listofFiles = folder.listFiles();
static String[] underFiles = folder.list();
public static void main(String[] args) throws IOException {
Main main = new Main();
main.walk(Directory);
}
public void walk( String path ) {
File root = new File( path );
File[] list = root.listFiles();
if (list == null) {
return;
}
for (File f : list) {
if ( f.isDirectory() ) {
walk( f.getAbsolutePath() );
System.out.println( "Dir:" + f.getAbsoluteFile() );
}
else {
System.out.println( "File:" + f.getName() );
}
}
}
The input is to give a directory path. The output will show all of the files in the given directory. How can I compare equal file names in this directory?
As I understand it, you want to locate directories that contain files with the same file name. For example, on a Windows machine, you may have several folders that contain image files. Usually each one of those folders will have a file named Thumbs.db. So you would like to know the names of the folders that contain a file named Thumbs.db.
The following code calls method walk of class java.nio.file.Files and manipulates the Stream returned by that method to create a Map where the Map key is the file name and the Map value is a List of all the folders that contain a file with that name.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class WalkTree {
public static void main(String[] args) {
Path path = Paths.get(args[0]);
try (Stream<Path> paths = Files.walk(path)) {
Map<Path, List<Path>> map = paths.filter(p -> Files.isRegularFile(p))
.collect(Collectors.toMap(p -> p.getFileName(),
p -> new ArrayList<Path>(List.of(p.getParent())),
(l1, l2) -> {l1.addAll(l2); return l1;}));
}
catch (IOException xIo) {
xIo.printStackTrace();
}
}
}
The first parameter to the toMap method, in the above code, is a Function that returns the Map key. The second parameter is another Function that returns the Map value. And the third parameter is a BinaryOperator that merges two different Map values that both have the same Map key.
Try this:
public static void main(String[] args) throws IOException {
String path = "/your/file-path/here";
try (Stream<Path> paths = Files.walk(Paths.get(path))) {
Map<String, List<Path>> map =
paths.filter(Files::isRegularFile)
.collect(groupingBy(p -> p.getFileName().toString()));
System.out.println(map);
}
}
Files.walk will walk all the hierarchy of files for you. The only thing you need to do is to consume the Paths from Stream.
If you still want to stick with your own code. Then you might do this instead:
public static void walk(String path, Map<String, List<String>> map) {
File root = new File(path);
File[] list = root.listFiles();
if (list == null) return;
for (File f : list) {
if (f.isDirectory()) {
walk(f.getAbsolutePath(), map);
System.out.println("Dir:" + f.getAbsoluteFile());
} else {
map.computeIfAbsent(f.getName(), k -> new ArrayList())
.add(f.getAbsolutePath());
System.out.println("File:" + f.getName());
}
}
}
and then:
public static void main(String[] args) {
String fileName = "/your/file-path/here";
Map<String, List<String>> map = new HashMap<>();
walk(fileName, map);
System.out.println(map);
}
Related
Please take a look at the code I have so far and if possible explain what I'm doing wrong. I'm trying to learn.
I made a little program to search for a type of file in a directory and all its sub-directories and copy them into another folder.
Code
import java.util.ArrayList;
import java.util.List;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
public class FandFandLoop {
public static void main(String[] args) {
final File folder = new File("C:/Users/ina/src");
List<String> result = new ArrayList<>();
search(".*\\.txt", folder, result);
File to = new File("C:/Users/ina/dest");
for (String s : result) {
System.out.println(s);
File from = new File(s);
try {
copyDir(from.toPath(), to.toPath());
System.out.println("done");
}
catch (IOException ex) {
ex.printStackTrace();
}
}
}
public static void copyDir(Path src, Path dest) throws IOException {
Files.walk(src)
.forEach(source -> {
try {
Files.copy(source, dest.resolve(src.relativize(source)),
StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
e.printStackTrace();
}
});
}
public static void search(final String pattern, final File folder, List<String> result) {
for (final File f : folder.listFiles()) {
if (f.isDirectory()) {
search(pattern, f, result);
}
if (f.isFile()) {
if (f.getName().matches(pattern)) {
result.add(f.getAbsolutePath());
}
}
}
}
}
It works, but what it actually does is to take my .txt files and write them into another file named dest without extension.
And at some point, it deletes the folder dest.
The deletion happens because of StandardCopyOption.REPLACE_EXISTING, if I understand this, but what I would have liked to obtain was that if several files had the same name then only one copy of it should be kept.
There is no need to call Files.walk on the matched source files.
You can improve this code by switching completely to using java.nio.file.Path and not mixing string paths and File objects. Additionally instead of calling File.listFiles() recursively you can use Files.walk or even better Files.find.
So you could instead use the following:
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.stream.Stream;
public class CopyFiles {
public static void copyFiles(Path src, Path dest, PathMatcher matcher, CopyOption... copyOptions) throws IOException {
// Argument validation
if (!Files.isDirectory(src)) {
throw new IllegalArgumentException("Source '" + src + "' is not a directory");
}
if (!Files.isDirectory(dest)) {
throw new IllegalArgumentException("Destination '" + dest + "' is not a directory");
}
Objects.requireNonNull(matcher);
Objects.requireNonNull(copyOptions);
BiPredicate<Path, BasicFileAttributes> filter = (path, attributes) -> attributes.isRegularFile() && matcher.matches(path);
// Use try-with-resources to close stream as soon as it is not longer needed
try (Stream<Path> files = Files.find(src, Integer.MAX_VALUE, filter)) {
files.forEach(file -> {
Path destFile = dest.resolve(src.relativize(file));
try {
copyFile(file, destFile, copyOptions);
}
// Stream methods do not allow checked exceptions, have to wrap it
catch (IOException ioException) {
throw new UncheckedIOException(ioException);
}
});
}
// Wrap UncheckedIOException; cannot unwrap it to get actual IOException
// because then information about the location where the exception was wrapped
// will get lost, see Files.find doc
catch (UncheckedIOException uncheckedIoException) {
throw new IOException(uncheckedIoException);
}
}
private static void copyFile(Path srcFile, Path destFile, CopyOption... copyOptions) throws IOException {
Path destParent = destFile.getParent();
// Parent might be null if dest is empty path
if (destParent != null) {
// Create parent directories before copying file
Files.createDirectories(destParent);
}
Files.copy(srcFile, destFile, copyOptions);
}
public static void main(String[] args) throws IOException {
Path srcDir = Paths.get("path/to/src");
Path destDir = Paths.get("path/to/dest");
// Could also use FileSystem.getPathMatcher
PathMatcher matcher = file -> file.getFileName().toString().endsWith(".txt");
copyFiles(srcDir, destDir, matcher);
}
}
I have a code here that can read all .txt file in 1 folder, it can print every content inside the .txt file to console. Then it moved to new folder.
The problem is: it has been read randomly, but i want to read the .txt file by it time-stamp, which is who have last edited time will be read at first...
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Basic {
public static void main(String[] args) throws IOException {
String source = "C:\\Users\\NN\\Documents\\Test1";
String target = "C:\\Users\\NN\\Documents\\Test2";
List<Path> filePaths = filePathsList(source); // Step 1: get all files from a directory
List<Path> filteredFilePaths = filter(filePaths); // Step 2: filter by ".txt"
Map<Path, List<String>> contentOfFiles = getContentOfFiles(filteredFilePaths); // Step 3: get content of files
move(filteredFilePaths, target); // Step 4: move files to destination
printToConsole(contentOfFiles); // Step 5: print content of files to console
}
public static List<Path> filePathsList(String directory) throws IOException {
List<Path> filePaths = new ArrayList<>();
DirectoryStream<Path> directoryStream = Files.newDirectoryStream(FileSystems.getDefault().getPath(directory));
for (Path path : directoryStream) {
filePaths.add(path);
}
return filePaths;
}
private static List<Path> filter(List<Path> filePaths) {
List<Path> filteredFilePaths = new ArrayList<>();
for (Path filePath : filePaths) {
if (filePath.getFileName().toString().endsWith(".txt")) {
filteredFilePaths.add(filePath);
}
}
return filteredFilePaths;
}
private static Map<Path, List<String>> getContentOfFiles(List<Path> filePaths) throws IOException {
Map<Path, List<String>> contentOfFiles = new HashMap<>();
for (Path filePath : filePaths) {
contentOfFiles.put(filePath, new ArrayList<>());
Files.readAllLines(filePath).forEach(contentOfFiles.get(filePath)::add);
}
return contentOfFiles;
}
private static void move(List<Path> filePaths, String target) throws IOException {
Path targetDir = FileSystems.getDefault().getPath(target);
if (!Files.isDirectory(targetDir)) {
targetDir = Files.createDirectories(Paths.get(target));
}
for (Path filePath : filePaths) {
System.out.println("Moving " + filePath.getFileName() + " to " + targetDir.toAbsolutePath());
Files.move(filePath, Paths.get(target, filePath.getFileName().toString()), StandardCopyOption.ATOMIC_MOVE);
}
}
private static void printToConsole(Map<Path, List<String>> contentOfFiles) {
System.out.println("Content of files:");
contentOfFiles.forEach((k,v) -> v.forEach(System.out::println));
}
}
You could use File.lastModified() and sort it by its date.
How can I go to each subfolder in a given directory and take a pdf file from there like wise collect all pdf from all subfolders and move to a common folder?.
I've tried below code which is failing.
import java.io.File;
import java.io.IOException;`enter code here`
import java.nio.file.Files;
import java.util.ArrayList;
public class PDFMover{
/**
* #param args
* #return
* #throws IOException
*/
public static void main(String[] args) throws IOException {
File mainfolder = new File("C:\\Users\\myuser\\Desktop\\X\\Report");
File[] fulllist = mainfolder.listFiles();
ArrayList<String> listofpath = new ArrayList<String>(fulllist.length);
for (File x : fulllist)
{
if (x.isDirectory())
{
System.out.println("Directory:" +x.getName());
}
else
{
System.out.println("Notfound");
}
}
String source = "C:\\Users\\myuser\\Desktop\\X\\Report";
String destination ="C:\\Users\\myuser\\Desktop\\Destination";
File f1 = new File(source);
File f2 = new File(destination);
for (File x : fulllist)
{
if(mainfolder.isDirectory())
{
Files.copy(f1.toPath(), f2.toPath());
}
}
}
}
If you use nio.Files the solution to find every file in every subdirectory would be:
import java.nio.file.FileSystems;
import java.nio.file.Files;
public class FileWalker
{
public static final String PATH = "C:\\Users\\myuser\\Desktop\\X\\Report";
public static void main(final String[] args) throws Exception
{
Files.walk(FileSystems.getDefault()
.getPath((PATH)))
.map(path -> path.getFileName())
.filter(name -> name.toString()
.toLowerCase()
.endsWith("pdf"))
.forEach(System.out::println);
}
}
Instead of System.out.println you have to copy the files.
You can either use a recursive function, or use an explicit stack to do this. You simply check each of the files to see if they match your selection criteria. If not and if it's a directory you put it in the stack and move on.
Here's some working code using this approach. It let's you find files with a particular extension down to a particular recurs depth. The getRecurseFiles() returns a list of canonical path strings.
import java.util.*;
import java.io.*;
class Tracker {
File[] list;
int depth;
public Tracker (File[] l, int d) {
this.list = l;
this.depth = d;
}
}
public class RecTraverse {
public static int MAX_DEPTH = 10;
List<String> getRecurseFiles (String dir) throws IOException {
List<String> requiredFiles = new ArrayList<>();
Stack<Tracker> rstack = new Stack<>();
File[] list = new File(dir).listFiles();
rstack.push(new Tracker(list, 1));
while (!rstack.empty()) {
Tracker tmp = rstack.pop();
for (int i=0; i<tmp.list.length; i++) {
File thisEntry = tmp.list[i];
String fileName = tmp.list[i].getCanonicalPath();
if (thisEntry.isFile()) {
int j = fileName.lastIndexOf('.');
if (j > 0) {
String extension = fileName.substring(j+1).toLowerCase();
if (extension.equals("pdf"))
requiredFiles.add(tmp.list[i].getCanonicalPath());
}
} else {
System.out.println(thisEntry.getCanonicalPath());
File[] thisEntryList = thisEntry.listFiles();
if (thisEntryList != null && tmp.depth+1 <= MAX_DEPTH) {
rstack.push(new Tracker(thisEntryList, tmp.depth+1));
}
}
}
}
return requiredFiles;
}
public static void main (String[] arg) {
try {
List<String> l = new RecTraverse().getRecurseFiles(".");
for (String s : l)
System.out.println(s);
} catch (IOException e) {
}
}
}
There is my code:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
public class CompareFile {
CompareFile() {}
boolean check = false;
int count = 0;
/*
* this method return a File type variable
* variable path - this parameter takes a path in specified root
* also it's a private method and he should be called with help by class object
*/
public File find(File path) throws FileNotFoundException {
PrintWriter writer = new PrintWriter("D:/Photos/name.txt");
ArrayList<String> buffer = new ArrayList<String>();
/*
* let's create array of files
* where must be all found files
* We use File[], and named 'files'
* variable files takes on list of found files
* with help by listFiles method, that
* return list of files and directories
*/
File[] files = path.listFiles();
//System.out.println(files.toString());
try {
/*
* we'll ought use the for each loop
* in this loop we'll create File type variable 'file'
* then we'll do iterating for each expression from variable files
*/
for (File file : files) {
//print all found files and directories
//if file or directory exists
if (file.isDirectory()) {
//recursively return file and directory
find(file);
}
else {
buffer.add(file.getName());
System.out.println(file);
}
}
}
catch (Exception e) {
System.out.print("Error");
}
finally{
if ( writer != null )
writer.close();
}
/*
Iterator<String> i = buffer.iterator();
while(i.hasNext()) {
System.out.println(i.next());
}*/
return path;
}
public static void main(String[] args) throws FileNotFoundException {
File mainFile = new File("D:/Photos/");
CompareFile main = new CompareFile();
main.find(mainFile);
}
}
If I use sort, after sorting, the result bad, because first row from dir "Photos",
and second row from directory in directory "Photos/sub" Let's look at
the screen: I think you understand)
http://s10.postimg.org/7hcw83z9x/image.png
You'll need to keep track of where you are in the tree, change the find method to take a path:
public File find(File path, string path="") throws FileNotFoundException
When you call the find method recursively:
find(file, path + file.getName() + "/")
Then when you add to the list, use
buffer.add(path + file.getName());
I'm working on this program to get all the files in the directory. For some reason I am getting a NullPointerException on Line 16. I don't know why though since this is a template that seemed to work in class with our teacher. Thanks.
import java.util.*;
import java.io.*;
public class FindDirectories {
public static void main(String[] args) {
if (args.length == 0) {
args = new String[] { ".." };
}
List<String> nextDir = new ArrayList<String>();
nextDir.add(args[0]); // either the one file, or the directory
try {
while(nextDir.size() > 0) { // size() is num of elements in List
File pathName = new File(nextDir.get(0)); // gets the element at the index of the List
String[] fileNames = pathName.list(); // lists all files in the directory
for(int i = 0; i < fileNames.length; i++) {
File f = new File(pathName.getPath(), fileNames[i]); // getPath converts abstract path to path in String,
// constructor creates new File object with fileName name
if (f.isDirectory()) {
System.out.println(f.getCanonicalPath());
nextDir.add(f.getPath());
}
else {
System.out.println(f);
}
}
nextDir.remove(0);
}
}
catch(IOException e) {
e.printStackTrace();
}
}
}
Check out the Javadoc for File.list(). Specifically:
Returns null if this abstract pathname does not denote a directory, or if an I/O error occurs.
In your code pathName.list(); must be returning null so pathName does not represent a valid directory, or an IO error occurred trying to get a list of files from that directory.
Use bellow snippet to get all the files from all the sub directories:
import java.io.File;
/**
*
* #author santoshk
*/
public class ListFiles {
File mainFolder = new File("F:\\personal");
public static void main(String[] args)
{
ListFiles lf = new ListFiles();
lf.getFiles(lf.mainFolder);
}
public void getFiles(File f){
File files[];
if(f.isFile())
System.out.println(f.getAbsolutePath());
else{
files = f.listFiles();
for (int i = 0; i < files.length; i++) {
getFiles(files[i]);
}
}
}
}
If you're getting a NullPointerException on line 16, it must mean that fileNames is null, so fileNames.length is invalid. Take a look at the javadoc for File.list and you'll see that pathName.list() can be null if pathName is not a directory, or if an exception occurs. So you'll just need to check whether fileNames is null before trying to use it.
import java.io.File;
import java.util.ArrayList;
import java.util.LinkedList;
public class FileEnumerator {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
// Prepare the List of files
String path = "C:/";
ArrayList<String> Files = new ArrayList<String>();
LinkedList<String> Dir = new LinkedList<String>();
File f = new File(path);
Dir.add(f.getAbsolutePath());
while(!Dir.isEmpty())
{
f = new File(Dir.pop());
if(f.isFile())
{
Files.add(f.getAbsolutePath());
}
else
{
String arr[] = f.list();
try
{
for(int i = 0;i<arr.length;i++)
{
Dir.add(f.getAbsolutePath()+"/"+arr[i]);
}
}
catch(NullPointerException exp)
{
Dir.remove(f.getAbsoluteFile());
}
}
}
//Print the files
for(int i = 0;i<Files.size();i++)
{
System.out.println(Files.get(i));
}
}
}
I think this code should work well. Although I have tested it just on Windows. But other OS will need at most small changes.
import java.io.*;
public class filedir
{
public static void main(String[] args)
{
try{
Files f = new File("C:\\");//the path required
String a[];
a=f.list();
for (int i = 0; i <a.length; i++) {
System.out.println(a[i]);
}
} catch(Exception e) {
System.err.println(e);
}
}
}