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.
Related
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
I am reading files from one folder, each folder can have various lines of records. So I am creating two arrayList here:
List<Address> addressList;
List<List<Address>> addressLists;
I am calling readIncomingFiles method which returns object of List<List<Address>>
// The code structure of method which reads incomingFiles
public List<List<Address>> readIncomingFiles() {
//some lines of code Processing data
if (!(addressList == null || addressList.size() == 0)) {
addressLists.add(addressList);
}
return addressLists;
}
Now in addressLists I have records from all files with all records. In main method I have process method where first it reads my objects addressLists which as all records. Suppose three files are there with three record each, it will have total 9 records.
void process() //main method {
this.addressLists=this.readIncomingFiles();
List<String> outgoingFileNames = this.getOutgoingFileName();
//Here I am creating a list for all outgoing files which will be generated and kept in destination folder.from getOutgoingFileName method
for (String outgoingFile : outgoingFileNames) {
if(validate file if file contains csv in output generated file name)
then call ProcessFile
ProcessFile()
for (List<AddressDto> listOfAddress : this.addressLists) {
for (AddressDto address : listOfAddress) {
this.csvOut = new OutputCsvDataDto();
//Process files and Records.
// Here OutputCsvDataDto returns data drom result generating method which writes records in OutputCsvDataDto List.
}
The problem is it reads all files and all records as it returns List<List<Address>, also the method getoutgoing file generates 3 output file one a time and returns a list. The code structure for outgoingfile method is pasted below:
public List<String> getOutgoingFileName {
for (File incomingFile : incomingFileFolder.listFiles()) {
outgoingFilenames.add("results_" + incomingFile.getName());
}
}
How can I read one record at a time? If I read one record at a time, how will I process other records? I am new in Java.
I'm not sure if I got you correctly, but let's sum it up:
there's one folder with many files,
these files contain variable count of lines,
each line is a record of some kind (presumably post address),
you want read all these files, process it one-by-one, by line and save output to a file, which name bases somehow on the input file
If all of the above is correct, then first let's start with the modification of the whole process, as currently you read all the files into memory and this is something you don't really want to do. What if each file takes, like 4GiB? So better approach is to process this whole thing in a manner more reassembling a "pipeline" than a "storage".
So, it goes more or less like this:
public static void main(String[] args) {
File incomingDir = new File(args[0]);
File outgoingDir = new File(args[1]);
for (File f : incomingDir.listFiles()) {
processFile(f, outgoingDir);
}
}
private static void processFile(File incomingFile, File outgoingDir) {
File outgoingFile = new File(outputDir, "results-" + incomingFile.getName());
for (String line : /* read lines from incomingFile */) {
Address address = parseAddress(line);
/* write address to outgoingFile */
}
}
private static Address parseAddress(String line) {
Address address;
/* do parsing */
return address;
}
Of course you need to adapt the code, probably use BufferedReader in while loop (instead of for loop in processFile as above), but it's more to sketch out the concept than give a "copy-paste" answer. And think how you can make this code work in parallel and if always does it make sense.
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
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();
}
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.