Extract FileName from getAbsolutePath() method - java

I'm using a method from this site to read all the files exist on the system hard drives, it's working fine, but i need to check that a certain file exists while searching.
to make the story short here is the line code which is reading the files
parseAllFiles(f.getAbsolutePath());
how can I assign the output from this method to a string so i can search iniside this string for the file I want, or there any way to add/change to this statement to get the filename directely in a string?
public static void parseAllFiles(String parentDirectory){
File[] filesInDirectory = new File(parentDirectory).listFiles();
if(filesInDirectory != null){
for(File f : filesInDirectory){
if(f.isDirectory()){
parseAllFiles(f.getAbsolutePath()); // get full path
}
System.out.println("Current File -> " + f);
}
}
}

Use objects rather than strings since they tend to offer useful functionality that strings don’t offer. In your case pass a File object or a Path object to your recursive method. I take it that you start out from a string, so have your public method accept a string and construct the first object.
public static void parseAllFiles(String parentDirectory) {
parseAllFiles(new File(parentDirectory));
}
private static void parseAllFiles(File dir) {
File[] filesInDirectory = dir.listFiles();
if (filesInDirectory != null) {
for (File f : filesInDirectory) {
String fileName = f.getName();
String fullPathName = f.getAbsolutePath();
System.out.println("Current File -> " + fileName);
System.out.println("Current path -> " + fullPathName);
if (f.isDirectory()) {
parseAllFiles(f);
}
}
}
}
I didn’t get whether you wanted only the file name or the full path name of the file, but the code shows how to extract each into a string. You may then search inside these two strings for whatever you are looking for.
java.nio since Java 7
I routinely use java.nio.file for file system operations. For everyday purposes I don’t find it better to work with than the older File class, but it does offer a wealth of options that the older class doesn’t offer. #Shahar Rotshtein in a comment mentioned the FileVisitor interface from java.nio.file. Depending on your exact requirements Files.walkFileTree passing your own FileVisitor may be the best option for you. I have not understood your real requirements well enough to offer a code example.
Links
java.nio.file documentation
Section Walking the file tree in the Oracle tutorial: Basic I/O

Related

Java updating file reference after renaming

Hi there I have a problem dealing with some legacy code.
I need a way to get the changed File from the parseFile() method up to the calling doWithFileList() method.
public static void main(String[] args) throws IOException {
File file1 = File.createTempFile("file1", ".tmp");
File file2 = File.createTempFile("file2", ".tmp");
ArrayList<File> fileList = new ArrayList<File>();
fileList.add(file1);
fileList.add(file2);
doWithFileList(fileList);
}
static void doWithFileList(List<File> fileList) {
for (File file : fileList) {
String result = parseFile(file);
}
//Do something with the (now incorrect) file objects
for (File file : fileList) {
// always false here
if (!file.exists()) {
System.out.println("File does not exist anymore");
}
}
}
private static String parseFile(File file) {
//1. Get information from the File
//2. Use this information to load an object from the Database
//3. return some property of this object
//4. depending on another property of the DB object rename the file
file.renameTo(new File(file.getAbsoluteFile() + ".renamed"));
return "valueParsedFromFile";
}
I know that File objects are immutable.
The problem is in my real world problem the parseFile() method at the moment only does Step step 1-3 but I need to add step 4.
The renaming is not a problem, but I need to get the new file name somehow to the calling method.
in the real life problem there is bigger stack trace across multiple objects between those methods.
What would be the best way to get the changed name of the file back to the beginning of the the call hierarchy where I can change the object in the list.
my best guess at the moment would be to create a ReturnObject that holds both the String to return and the new File object. But then I have to refactor a bunch of methods on my way up so I would need to create a bunch of different return objects.
The following possiblities come to mind:
pass a mutable object, e.g. a new String[1] and set it there. (Mega-ugly, because you have side effects and not a pure function anymore) (On the other hand: you already have side-effects - go figure ;-))
Use a generic return object like String[], a Map, a Pair-implementation that you can find in various utilities (e.g. org.colllib.datastruct.Pair)
Use a hand-crafted return object
Personally, I'd probably go with (2), but it also might be (3)
Using a ReturnObjet seem to be the sole solution as far as I know.

Check for new files in a loop - java

I have a program that needs to read files. I need to check every 10 seconds if there is new files.
To do that, I've made this :
ArrayList<File>oldFiles = new ArrayList<File>();
ArrayList<File>files=new ArrayList<File>();
while(isFinished != true){
files=listFilesForFolder(folder);
if(oldFiles.size() != files.size()){
System.out.println("Here is when a new file(s) is(are) in the folder");
}
Thread.sleep(10000);
}
Basically, the listFilesForFolder is getting a folder destination, and check the files in there.
My problem : My program does every loop my reading function on every file. I want to do my reading function ONLY on new files.
How can I do something like :
new files - old files = my files I want to read.
Rather than your approach why not store the DateTime of the last time that you checked.
Then compare this time to the File.lastModified value
The problem with your appraoch is that the array sizes will be different even in a file is deleted, and will be the same if one file is deleted and one file is added.
Rather than comparing old and new files, why not write a method to just return Last Modified Files.
public static ArrayList<File> listLastModifiedFiles(File folder,
long sleepDuration) throws Exception {
ArrayList<File> newFileList = new ArrayList<File>();
for (File fileEntry : folder.listFiles())
if ((System.currentTimeMillis() - fileEntry.lastModified()) <= sleepDuration)
newFileList.add(fileEntry);
return newFileList;
}
//Sample usage:
long sleepDuration = 10000;
ArrayList<File> newFileList;
int counter = 10;
while (counter-- > 0) {
newFileList = listLastModifiedFiles(folder, sleepDuration);
for (File File : newFileList)
System.out.println(File.getName());
Thread.sleep(sleepDuration);
}
You can use sets. Instead of returning an ArrayList, you could return a set instead.
newFiles.removeAll(oldFiles);
would then give you all the files that are not in the old set. I'm not saying that working with the modification date as Scary Wombat has pointed out is a worse idea, I'm just offering another solution.
Additionally, you have to modify your oldFiles to hold all files you've already encountered. The following example I think does what you're trying to achieve.
private static Set<File> findFilesIn(File directory) {
// Or whatever logic you have for finding files
return new HashSet<File>(Arrays.asList(directory.listFiles()));
}
public static void main(String[] args) throws Throwable {
Set<File> allFiles = new HashSet<File>(); // Renamed from oldFiles
Set<File> newFiles = new HashSet<File>();
File dir = new File("/tmp/stackoverflow/");
while (true) {
allFiles.addAll(newFiles); // Add files from last round to collection of all files
newFiles = findFilesIn(dir);
newFiles.removeAll(allFiles); // Remove all the ones we already know.
System.out.println(String.format("Found %d new files: %s", newFiles.size(), newFiles));
System.out.println("Sleeping...");
Thread.sleep(5000);
}
}
Sets are a more appropiate data storage for your case since you don't need any order in your collection of files and can benefit from faster lookup times (when using a HashSet).
Assuming that you only need to detect new files, not modified ones, and no file will be removed while your code is running:
ArrayList implements removeAll(Collection c), which does exactly what you want:
Removes from this list all of its elements that are contained in the
specified collection.
You might want to consider using the Java WatchService API which uses the low level operating system to notify you of changes to the file system. It's more efficient and faster than listing the files in directory.
There is a tutorial at Watching a Directory for Changes and the API is documented here: Interface WatchService

Recursion: Checking for files in Directories and reading them

Before you speculate something like "This guy is asking for homework help", I'll go ahead and clear any doubts you may have and say yes, this is related to homework. However, I hope that does not take away from the learning that this question provides to me and/or anyone who reads this in the future.
Background: We're currently working on recursion and our assignment asks that we write a program that uses command arguments to check a directory and its file contents for a string(that is also a command argument). We must use recursion for this.
-I want to make this clear that I UNDERSTAND WHAT THE ASSIGNMENT IS ASKING
I am simply asking, how would this work recursively because I just don't get it.
We did a problem where we had to find the size of a directory and it made sense, but I don't get how to check if something is a directory or file and based on that we read its contents or go deeper into the directory until we find a file.
Here's what I've currently done. Not too sure how wrong this is as I'm basing entirely off of the 'check the size of a directory' assignment we previously did:
The folder that I'm checking is something like this:
Directory ---> files --inside main directory --->> Two directories ----> files within both of those directories
public class SearchingForStrings {
public static void main(String[] args) {
String path = "."; // default location of this project
File sf = new File(path);
String mysteriesDirectory = args[0];
String keyString = args[1];
countLinesWithString(sf, mysteriesDirectory, keyString);
}
public static int countLinesWithString(File startPath, String mysteriesDirectory, String keyString) {
if(!startPath.exists()) {
throw new IllegalArgumentException("File " + startPath + " does not exist!");
} else if(startPath.isFile()) {
return Integer.parseInt(startPath.getAbsolutePath()); // Just to show where the file is I located the parsing is just to stop an error from flagging on this part; Going to ask professor if it's okay with him
// this is where we would begin reading the contents of the files
} else if(startPath.isDirectory()) {
// This is where our recursion would take place: essentially
// we will be going 'deeper' into the directory until we find a file
//File[] subFiles = startPath.listFiles();
countLinesWithString(startPath, mysteriesDirectory, keyString);
} else {
throw new IllegalStateException("Unknown file type: " + startPath);
}
}
}
In short: Could someone explain how recursion would work if you wanted to go deeper into a director(y/ies)?
I'll give this a try. It's something that is easier to explain than to understand.
The recursive method, on which you have made a decent start, might be documented as follows:
"For a given directory: for each file in the directory, count all the lines which contain a given string; for each directory in the directory, recurse".
The recursion is possible - and useful - because your original target is a container, and one of the types of things it can contain is another container.
So think of the counting method like this:
int countLines(dir, string) // the string could be an instance variable, also, and not passed in
{
var countedLines = 0;
for each item in dir:
if item is file, countedLines += matchedLinesInFile(item, string);
else if item is dir, countedLines += countLines(item, string);
else throw up; // or throw an exception -- your choice
}
then call countLines from an exterior method with the original dir to use, plus the string.
One of the things that trips people up about recursion is that, after you get it written, it doesn't seem possible that it can do all that it does. But think through the above for different scenarios. If the dir passed in has files and no dirs, it will accumulate countedLines for each file in the dir, and return the result. That's what you want.
If the dir does contain other dirs, then for each one of those, you're going to call the routine and start on that contained dir. The call will accumulate countedLines for each file in that dir, and call itself for each dir recursively down the tree, until it reaches a dir that has no dirs in it. And it still counts lines in those, it just doesn't have any further down to recurse.
At the lowest level, it is going to accumulate those lines and return them. Then the second-lowest level will get that total to add to its total, and start the return trips back up the recursion tree.
Does that explain it any better?
Just help you get started with recursion check this :
It will recursively go from base directory printing all the folders and files.
Modify this to your requirements. Try and let us know.
import java.io.File;
public class Test {
public static void getResource(final String resourcePath) {
File file = new File(resourcePath);
if (file.isFile()) {
System.out.println("File Name : " + file.getName());
return;
} else {
File[] listFiles = file.listFiles();
if (listFiles != null) {
for (File resourceInDirectory : listFiles) {
if (!resourceInDirectory.isFile()) {
System.out.println("Folder "
+ resourceInDirectory.getAbsolutePath());
getResource(resourceInDirectory.getAbsolutePath());
} else {
getResource(resourceInDirectory.getAbsolutePath());
}
}
}
}
}
public static void main(String[] args) {
final String folderPath = "C:/Test";
getResource(folderPath);
}
}

I want to find a value from an array

Here's my java code:
import java.io.File;
import java.util.Arrays;
public class mainClass {
public static void main(String... args) {
File[] files = new File("%appdata%").listFiles();
showFiles(files);
System.out.println( Arrays.toString( files ) );
if (Arrays.asList(files).contains(".minecraft")) {
System.out.println("Success!");
}
}
public static void showFiles(File[] files) {
}
}
I want code above to check if .minecraft folder exists in %appdata%. I am total N00B to Java. I have worked with PHP, but doesn't seem to help me :) Please help, it annoys me.
-Simon
If you are interested in finding only the ".minecraft" file it would be much easier to:
File appdata = new File("%appdata%");
File minecraft = new File(appdata, ".minecraft");
if (minecraft.exists()) {
System.out.println("Success");
}
EDIT: Based on comment, (and I'm a linux guy mostly), you need to use the correct %APPDATA% location: How do I get the value of Windows' %APPDATA% location variable in Java?
The problem is that .minecraftis a hidden folder. You need to access the folder like this:
File directory = new File("%appdata%");
File[] hiddenFiles = directory.listFiles((FileFilter) HiddenFileFilter.HIDDEN);
for (File hiddenFile: hiddenFiles) {
System.out.println("hidden file: " + hiddenFile.getCanonicalPath());
}
As rolfl mentioned, there is a better way to look for a single file.
That said, your code isn't performing a proper check. You are creating an array of File objects, converting the array to a List, and then checking the list for a String value. The String value will never match a File object.
If you want to find a single file, use rolfl's answer. If you want to fix your code specifically, here's something to get your started:
You need to iterate over the list of files. What do you gain by converting to a List?
You need to find a way to match a File's name with a String name. What method might you call on the File object to get its name?
You need to do a String comparison between the File's name and ".minecraft". What might that comparison look like?
Please note: reference L.Butz answer as well; I haven't accessed hidden files in Java, so it's possible there's an extra step you need to get access to them.
%appdata%is an environment variable and as such it will not be automatically resolved by File. So you need to resolve it before listing it. This is done using System#getenv
#Test
public void dirExistsInAppData() {
Assert.assertTrue(dirExistsInAppData(".minecraft"));
}
private boolean dirExistsInAppData(final String dirname) {
File dir = new File(System.getenv("APPDATA"), dirname);
return dir.exists() && dir.isDirectory();
}

How to check whether a (String) location is a valid saving path in Java?

I am receiving a string from user which should be used as a location to save content to a file. This string should contain enough information, like a directory + file name.
My question is, how can I check whether the provided string is a valid path to save content to a file (at least in theory)?
It does not matter whether directories are created or not, or whether one has proper access to the location itself. I am only interested in checking the structure of the provided string.
How should I proceed? I was thinking about creating a File object, then extracting its URI. Is there any better way?
You can use File.getCanonicalPath() to validate according the current OS rules.
import java.io.File;
import java.io.IOException;
public class FileUtils {
public static boolean isFilenameValid(String file) {
File f = new File(file);
try {
f.getCanonicalPath();
return true;
}
catch (IOException e) {
return false;
}
}
public static void main(String args[]) throws Exception {
// true
System.out.println(FileUtils.isFilenameValid("well.txt"));
System.out.println(FileUtils.isFilenameValid("well well.txt"));
System.out.println(FileUtils.isFilenameValid(""));
//false
System.out.println(FileUtils.isFilenameValid("test.T*T"));
System.out.println(FileUtils.isFilenameValid("test|.TXT"));
System.out.println(FileUtils.isFilenameValid("te?st.TXT"));
System.out.println(FileUtils.isFilenameValid("con.TXT")); // windows
System.out.println(FileUtils.isFilenameValid("prn.TXT")); // windows
}
}
Have you looked at Apache Commons IO? This library includes various things for handling path information which may help e.g. FilenameUtils.getPath(String filename) which returns the path from a full filename.
Easiest: try to save, listen for exceptions.
The only time I'd do something more complicated would be if the writing was to be deferred, and you want to give the user his feedback now.
Here is what I have so far:
private static boolean checkLocation(String toCheck) {
// If null, we necessarily miss the directory section
if ( toCheck == null ) {
System.out.println("Missing directory section");
return false;
}
String retrName = new File(toCheck).toURI().toString();
// Are we dealing with a directory?
if ( retrName.charAt(retrName.length()-1) == '/') {
System.out.println("Missing file name");
return false;
}
return true;
}
This tells me whether I have a proper directory structure and whether I am pointing to a directory rather than a file. I do not need I/O access.
I have noticed that if I use the File.createNewFile() method on a location pointing explicitly to a directory (which does not exist yet), Java creates a file with no extension, which is plain wrong. Either it should create a directory or it should throw some kind of error.
Also, the File constructors tend to add the current directory if none is provided in the argument. It is not documented, but no real harm in my case.
If anyone has a better solution, I'll approve it.
EDIT
I have finally combined the above with the input from RealHowTo.

Categories

Resources