I want to write Java codes that will meet the following requirements:
Detect multiple devices (removable storage) connected to the laptop
List down all devices connected to the laptop
Allow users to choose which device that should be used by the Java program
For example, when there are 2 USB devices, the Java program will detect them and then list them as (e.g. F:\, G:). Following this, the users can choose which device to use. Is there any way to do so?
I found this website http://www.snip2code.com/Snippet/506/Detect-USB-removable-drive-in-Java useful to detect my thumbdrive that is connected, however, it is not able to detect more than one device.
Detect.java
public class Detect
{
public String USBDetect()
{
String driveLetter = "";
FileSystemView fsv = FileSystemView.getFileSystemView();
File[] f = File.listRoots();
for (int i = 0; i < f.length; i++)
{
String drive = f[i].getPath();
String displayName = fsv.getSystemDisplayName(f[i]);
String type = fsv.getSystemTypeDescription(f[i]);
boolean isDrive = fsv.isDrive(f[i]);
boolean isFloppy = fsv.isFloppyDrive(f[i]);
boolean canRead = f[i].canRead();
boolean canWrite = f[i].canWrite();
if (canRead && canWrite && !isFloppy && isDrive && (type.toLowerCase().contains("removable") || type.toLowerCase().contains("rimovibile")))
{
//log.info("Detected PEN Drive: " + drive + " - "+ displayName);
driveLetter = drive;
break;
}
}
/*if (driveLetter.equals(""))
{
System.out.println("Not found!");
}
else
{
System.out.println(driveLetter);
}
*/
//System.out.println(driveLetter);
return driveLetter;
}
}
List.java
public class List
{
public static void main(String[] args)
{
File[] units = File.listRoots();
for(File unit:units)
{
System.out.println(unit.getAbsolutePath());
}
}
}
This code helps me detect more than 1 removable drive but it also lists down the local drives. I believe I should include in some parts from the Detect.java for it to detect only removable drives. As for 2. and 3. I have not tried yet because I do not know how to start, since I have not found any relevant websites to reference to. I hope that you can provide me with any useful websites or codes that could meet the requirements above. Sorry I am new to Java.
import java.io.File;
import javax.swing.filechooser.FileSystemView;
public class Detect
{
public static void main(String[] args)
{
Detect test = new Detect();
test.USBDetect();
}
public void USBDetect()
{
String driveLetter = "";
FileSystemView fsv = FileSystemView.getFileSystemView();
File[] f = File.listRoots();
for (int i = 0; i < f.length; i++)
{
String drive = f[i].getPath();
String displayName = fsv.getSystemDisplayName(f[i]);
String type = fsv.getSystemTypeDescription(f[i]);
boolean isDrive = fsv.isDrive(f[i]);
boolean isFloppy = fsv.isFloppyDrive(f[i]);
boolean canRead = f[i].canRead();
boolean canWrite = f[i].canWrite();
if (canRead && canWrite && !isFloppy && isDrive && (type.toLowerCase().contains("removable") || type.toLowerCase().contains("rimovibile")))
{
//log.info("Detected PEN Drive: " + drive + " - "+ displayName);
driveLetter = drive;
System.out.println(driveLetter);
}
}
/*if (driveLetter.equals(""))
{
System.out.println("Not found!");
}
else
{
System.out.println(driveLetter);
}*/
//System.out.println(driveLetter);
}
}
Related
I was wondering how I could implement an ArgumentCompleter such that if I complete a full and valid command, then it would begin tab completing for a new command.
I would have assumed it could be constructed doing something like this:
final ConsoleReader consoleReader = new ConsoleReader()
final ArgumentCompleter cyclicalArgument = new ArgumentCompleter();
cyclicalArgument.getCompleters().addAll(Arrays.asList(
new StringsCompleter("foo"),
new StringsCompleter("bar"),
cyclicalArgument));
consoleReader.addCompleter(cyclicalArgument);
consoleReader.readLine();
However right now this stops working after tab completeing the first foo bar
Is anyone familiar enough with the library to tell me how I would go about implementing this? Or is there a known way to do this that I am missing? Also this is using JLine2.
That was quite a task :-)
It is handled by the completer you are using. The complete() method of the completer has to use for the search only what comes after the last blank.
If you look for example at the FileNameCompleter of the library: this is not done at all, so you will find no completion, because the completer searches for <input1> <input2> and not only for <input2> :-)
You will have to do your own implementation of a completer that is able to find input2.
Additionally the CompletionHandler has to append what you found to what you already typed.
Here is a basic implementation changing the default FileNameCompleter:
protected int matchFiles(final String buffer, final String translated, final File[] files,
final List<CharSequence> candidates) {
// THIS IS NEW
String[] allWords = translated.split(" ");
String lastWord = allWords[allWords.length - 1];
// the lastWord is used when searching the files now
// ---
if (files == null) {
return -1;
}
int matches = 0;
// first pass: just count the matches
for (File file : files) {
if (file.getAbsolutePath().startsWith(lastWord)) {
matches++;
}
}
for (File file : files) {
if (file.getAbsolutePath().startsWith(lastWord)) {
CharSequence name = file.getName() + (matches == 1 && file.isDirectory() ? this.separator() : " ");
candidates.add(this.render(file, name).toString());
}
}
final int index = buffer.lastIndexOf(this.separator());
return index + this.separator().length();
}
And here the complete()-Method of the CompletionHandler changing the default CandidateListCompletionHandler:
#Override
public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos)
throws IOException {
CursorBuffer buf = reader.getCursorBuffer();
// THIS IS NEW
String[] allWords = buf.toString().split(" ");
String firstWords = "";
if (allWords.length > 1) {
for (int i = 0; i < allWords.length - 1; i++) {
firstWords += allWords[i] + " ";
}
}
//-----
// if there is only one completion, then fill in the buffer
if (candidates.size() == 1) {
String value = Ansi.stripAnsi(candidates.get(0).toString());
if (buf.cursor == buf.buffer.length() && this.printSpaceAfterFullCompletion && !value.endsWith(" ")) {
value += " ";
}
// fail if the only candidate is the same as the current buffer
if (value.equals(buf.toString())) {
return false;
}
CandidateListCompletionHandler.setBuffer(reader, firstWords + " " + value, pos);
return true;
} else if (candidates.size() > 1) {
String value = this.getUnambiguousCompletions(candidates);
CandidateListCompletionHandler.setBuffer(reader, value, pos);
}
CandidateListCompletionHandler.printCandidates(reader, candidates);
// redraw the current console buffer
reader.drawLine();
return true;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
First, I keep getting a NullPointerException on the line I put in ** below.
Second, my program is giving the wrong output (I somehow got it to work but then it went back to error). It must be a logic error. I have a file directory.txt of 11 lines, each with a name on it. When I run my program to try to find a certain name, it only finds the first name on the first line and everything else, it can't find. How can I fix these 2 errors?
I have 2 classes. This is the first class Directory:
import java.util.*;
import java.io.*;
public class Directory {
//public static void main(String[] args) {
final int maxDirectorySize = 1024;
String directory[] = new String[maxDirectorySize];
int directorySize = 0;
File directoryFile = null;
Scanner directoryDataIn = null;
public Directory(String directoryFileName) {
directoryFile = new File(directoryFileName);
try {
directoryDataIn = new Scanner(directoryFile);
}
catch (FileNotFoundException e) {
System.out.println("File is not found, exiting!" + directoryFileName);
System.exit(0);
}
while (directoryDataIn.hasNext()) {
directory[directorySize++] = directoryDataIn.nextLine();
}
}
public boolean inDirectory(String name) {
boolean inDir = true;
for (int i = 0; i < directory.length; i++) {
**if (directory[i].equalsIgnoreCase(name))**
inDir = true;
else
inDir = false;
}
return inDir;
}
public boolean add(String name) {
if (directory.length == 1024)
return false;
for (int i = 0; i < directory.length; i++) {
if (directory[i].equalsIgnoreCase(name))
return false;
else
directory[directorySize++] = name;
return true;
}
return false;
}
public boolean delete(String name) {
for (int i = 0; i < directory.length; i++) {
if (directory[i].equalsIgnoreCase(name)) {
directory[i] = null;
return true;
}
else
return false;
}
return false;
}
public void closeDirectory() {
directoryDataIn.close();
PrintStream directoryDataOut = null;
try {
directoryDataOut = new PrintStream(directoryFile);
}
catch (FileNotFoundException e) {
System.out.printf("File %s not found, exiting!", directoryFile);
System.exit(0);
}
String originalDirectory[] = {"Mike","Jim","Barry","Cristian","Vincent","Chengjun","susan","ng","serena"};
if (originalDirectory == directory)
System.exit(0);
else
for (int i = 0; i < directorySize; i++)
directoryDataOut.println(directory[i]);
directoryDataOut.close();
}
}
AND this is my second class which I'm trying to run but I keep getting exception main thread NullPointerException.
import java.io.*;
import java.util.*;
public class DirectoryWithObjectDesign {
public static void main(String[] args) throws IOException {
String directoryDataFile = "Directory.txt";
Directory d = new Directory(directoryDataFile);
Scanner stdin = new Scanner(System.in);
System.out.println("Directory Server is Ready!");
System.out.println("Format: command name");
System.out.println("Enter ^Z to end");
while (stdin.hasNext()) {
String command = stdin.next();
String name = stdin.next();
if (command.equalsIgnoreCase("find")) {
if (d.inDirectory(name))
System.out.println(name + " is in the directory");
else
System.out.println(name + " is NOT in the directory");
}
else if (command.equalsIgnoreCase("add")) {
if (d.add(name))
System.out.println(name + " added");
else
System.out.println(name + " cannot add! " + "no more space or already in directory");
}
else if (command.equalsIgnoreCase("delete")) {
if (d.delete(name))
System.out.println(name + " deleted");
else
System.out.println(name + " NOT in directory");
}
else {
System.out.println("bad command, try again");
}
}
}
}
This code:
while (directoryDataIn.hasNext()) {
directory[directorySize++] = directoryDataIn.nextLine();
}
will only fill up as much of directory as there are lines in the input file (11 according to your question).
This code:
for (int i = 0; i < directory.length; i++) {
**if (directory[i].equalsIgnoreCase(name))**
will loop over every entry in directory, up to its length (1024).
Since 1013 of those entries are null, trying to run equalsIgnoreCase() on them will result in a NPE.
Edit
You can solve this one of several ways. For instance, you could
keep track of the number of lines you read, and only read up to that point
check each entry to see if it is null before evaluating it
use a dynamically sized data structure instead of an array, such as ArrayList
perform the check on the known value (e.g. if (name.equalsIgnoreCase(directory[i])))
etc.
Change
for (int i = 0; i < directory.length; i++) {
To
for (int i = 0; i < directorySize; i++ ){
directorySize is already Keeping track of the number of entries so any array entries above that will be null. Therefore trying to call equalsIgnoreCase() on them will get a NPE.
Actually this looks like a prime use for ArrayList rather than array. The list will expand as you need it and List.size() will give you the correct length.
I have been recently trying to work on Cloud Computing as a part of my College assignment.
I have been trying to implement a new Load Balancing algorithm, (which has been proposed in some research paper) using CloudSim.
Please help me out with this algorithm, I have some major issues implementing it.
This is the code
/*
* Title: Load Balancing in Cloud Computing
*/
package org.cloudbus.cloudsim;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class MyPolicyNew extends VmAllocationPolicy {
private Map<String, Host> vmTable;
private Map<String, Integer> usedPes;
private List<Integer> freePes;
private int status[] = new int[100];
public MyPolicyNew(List<? extends Host> list) {
super(list);
setFreePes(new ArrayList<Integer>());
for (Host host : getHostList()) {
getFreePes().add(host.getPesNumber());
}
setVmTable(new HashMap<String, Host>());
setUsedPes(new HashMap<String, Integer>());
}
#Override
public boolean allocateHostForVm(Vm vm) {
int idx = -1;
int requiredPes;
requiredPes = vm.getPesNumber();
boolean result = false;
int tries = 0;
List<Integer> freePesTmp = new ArrayList<Integer>();
for (Integer freePes : getFreePes()) {
freePesTmp.add(freePes);
}
int tempstatus[] = new int[100];
for(int j=0; j<100; j++){
tempstatus[j]= status[j];
}
if (!getVmTable().containsKey(vm.getUid())) {
do {
int moreFree = Integer.MIN_VALUE;
for (int i=0; i < freePesTmp.size(); i++) {
if ((freePesTmp.get(i) > moreFree) && (tempstatus[i]!=1)) {
moreFree = freePesTmp.get(i);
idx = i;
}
tempstatus[idx]=1;
int flag=0;
for(int j=0; j< freePesTmp.size(); j++)
{ //
if(tempstatus[j]==1)
flag=1;
else
flag=0;
}
if(flag==1){
moreFree = Integer.MIN_VALUE;
for (int k=0; k < freePesTmp.size(); k++) {
if (freePesTmp.get(k) > moreFree) {
moreFree = freePesTmp.get(k);
idx = k;
}
}
}
}
Host host = getHostList().get(idx);
result = host.vmCreate(vm);
if (result) {
getVmTable().put(vm.getUid(), host);
getUsedPes().put(vm.getUid(), requiredPes);
getFreePes().set(idx, getFreePes().get(idx) - requiredPes);
status[idx]=1;
result = true;
break;
}
else {
freePesTmp.set(idx, Integer.MIN_VALUE);
tempstatus[idx]=0;
}
tries++;
}while(!result && tries < getFreePes().size());
}
return result;
}
#Override
public void deallocateHostForVm(Vm vm) {
Host host = getVmTable().remove(vm.getUid());
int idx = getHostList().indexOf(host);
int pes = getUsedPes().remove(vm.getUid());
if (host != null) {
host.vmDestroy(vm);
status[idx]= 0;
}
}
getFreePes().set(idx, getFreePes().get(idx) + pes);
#Override
public Host getHost(Vm vm) {
return getVmTable().get(vm.getUid());
}
#Override
public Host getHost(int vmId, int userId) {
return getVmTable().get(Vm.getUid(userId, vmId));
}
public Map<String, Host> getVmTable() {
return vmTable;
}
protected void setVmTable(Map<String, Host> vmTable) {
this.vmTable = vmTable;
}
protected Map<String, Integer> getUsedPes() {
return usedPes;
}
protected void setUsedPes(Map<String, Integer> usedPes) {
this.usedPes = usedPes;
}
protected List<Integer> getFreePes() {
return freePes;
}
protected void setFreePes(List<Integer> freePes) {
this.freePes = freePes;
}
#Override
public List<Map<String, Object>> optimizeAllocation(List<? extends Vm> vmList) {
return null;
}
#Override
public boolean allocateHostForVm(Vm vm, Host host) {
if (host.vmCreate(vm)){
getVmTable().put(vm.getUid(), host);
Log.formatLine("%.2f: VM #" + vm.getId() + " has been allocated to the host #" + host.getId(), CloudSim.clock());
return true;
}
return false;
}
}
Where ever I use the function getFreePes() my NetBeans compiler gives an error void cannot be deferenced and cannot find symbol getFreePes().
Basic idea behind the algorithm:: The algorithm checks if there are any free hosts in the data center and if there are any then it assigns a process to that host and decreases the number of free processors with that host. If there are no free hosts, but have some free processors then it checks the host with the maximum number of processors and assigns the new incoming process to that host..
Please help me out with this code, I am not very good at Java either, I have been more of a C/C++ coder, so, I am having a bit of problem dealing with things and further this a new library to me so I am not used to much of its features and function, a few of my seniors have helped me come up with this code, but now its not working, please help me guys.
Thanks for any help in advance. :)
This is the policy defined by the VmAllocationPolicySimple, so you don't need to implement it. It's a worst-fit policy that selects the Host with the fewest PEs in use to run a VM.
If you want to use different policies such as Best Fit, First Fit or implement your own policy, you can try CloudSim Plus, a state-of-the-art, full-featured, actively-maintained CloudSim fork. To create your own policy you just need to extend VmAllocationPolicyAbstract class and implement the Optional<Host> findHostForVm(final Vm vm) method. This way, you don't need to worry about all the internal details of the class.
As an example, the method below is all the code used in CloudSim Plus' VmAllocationPolicySimple class to implement the Host worst-fit host allocation policy:
public Optional<Host> findHostForVm(final Vm vm) {
final Map<Host, Long> map = getHostFreePesMap();
return map.entrySet()
.stream()
.filter(e -> e.getKey().isSuitableForVm(vm))
.max(Comparator.comparingLong(Map.Entry::getValue))
.map(Map.Entry::getKey);
}
And in CloudSim Plus, you don't even need to create a VmAllocationPolicy subclass to implement a custom policy. Check the RandomVmAllocationPolicyExample.java for details.
I do not know which version of cloudsim you are using. But I am also working on cloudsim version 3.0.3 and I have implemented also some load balancing policies.
This is the policy I have implemented. Code is not written in good optimized way but it is working. You can give it a try. This is mynewVmallocationpolicy. I think you can see what you have mistaken.
public boolean allocateHostForVm(Vm vm) {
int requiredPes = vm.getNumberOfPes();
// int requiredram = vm.getRam();
int freeramh1=0;
int freeramh2=0;
int freepesh1=0;
int freepesh2=0;
boolean result = false;
int tries = 0;
List<Integer> freePesTmp = new ArrayList<Integer>();
for (Integer freePes : getFreePes()) {
freePesTmp.add(freePes);
}
List <Host> hostList =getHostList();
if (!getVmTable().containsKey(vm.getUid())) { // if this vm was not created
do {// we still trying until we find a host or until we try all of them
int idx = -1;
// we want the host with less pes in use
Host h1=hostList.get(0);
int j=0;
idx=0;
for (int i = 1; i < freePesTmp.size(); i++) {
Host h2=hostList.get(i);
freeramh1=h1.getRamProvisioner().getAvailableRam();
freeramh2=h2.getRamProvisioner().getAvailableRam();
freepesh1=freePesTmp.get(j);
freepesh2=freePesTmp.get(i);
// Log.printLine( " freeram "+ freeramh1 + "h2" + freeramh2 + "free pes " + freepesh1 + "h2" + freepesh2);
double diffram=0.0,diffpes=0.0;
if(freeramh2!=0 || freeramh1!=0){
diffram= (1.0*(freeramh2-freeramh1)/(freeramh2+freeramh1));
// Log.printLine( " inside diffram " + diffram);
}
else
Log.printLine( " fault in ram " );
if(freepesh2!=0 || freepesh1!=0){
diffpes=(1.0*(freepesh1-freepesh2)/(freepesh1+freepesh2)) ;
//Log.printLine( " inside diffpes " + diffpes);
}
else
Log.printLine( " fault in pes ");
//Log.printLine( " diffram,diffpes "+ diffram + "diff pes " + diffpes );
if(diffram==diffpes || diffpes>diffram){
idx=j;
}
else{
h1=h2;
j=i;
idx=i;
break;
}
}
Host host = getHostList().get(idx);
result = host.vmCreate(vm);
if (result) { // if vm were succesfully created in the host
Log.printLine( " vm " + "created" + "host" + idx);
getVmTable().put(vm.getUid(), host);
getUsedPes().put(vm.getUid(), requiredPes);
getFreePes().set(idx, getFreePes().get(idx) - requiredPes);
result = true;
break;
} else {
freePesTmp.set(idx, Integer.MIN_VALUE);
}
tries++;
} while (!result && tries < getFreePes().size());
}
return result;
}
This code is working fine. You can check whats wrong.
I am using Java codes to find a file that ends with a certain extension in a detected removable storage. I am trying to link the two codes together but I am not sure on how I can do so. These are the codes I am using:
DetectDrive.java
import java.io.*;
import java.util.*;
import javax.swing.filechooser.FileSystemView;
public class DetectDrive
{
public String USBDetect()
{
String driveLetter = "";
FileSystemView fsv = FileSystemView.getFileSystemView();
File[] f = File.listRoots();
for (int i = 0; i < f.length; i++)
{
String drive = f[i].getPath();
String displayName = fsv.getSystemDisplayName(f[i]);
String type = fsv.getSystemTypeDescription(f[i]);
boolean isDrive = fsv.isDrive(f[i]);
boolean isFloppy = fsv.isFloppyDrive(f[i]);
boolean canRead = f[i].canRead();
boolean canWrite = f[i].canWrite();
if (canRead && canWrite && !isFloppy && isDrive && (type.toLowerCase().contains("removable") || type.toLowerCase().contains("rimovibile")))
{
//log.info("Detected PEN Drive: " + drive + " - "+ displayName);
driveLetter = drive;
break;
}
}
/*if (driveLetter.equals(""))
{
System.out.println("Not found!");
}
else
{
System.out.println(driveLetter);
}
*/
//System.out.println(driveLetter);
return driveLetter;
}
}
FileSarch.java
import java.io.*;
public class FileSearch
{
public String find(File dir)
{
String pattern = ".raw";
File listFile[] = dir.listFiles();
if (listFile != null)
{
for (int i=0; i<listFile.length; i++)
{
if (listFile[i].isDirectory())
{
find(listFile[i]);
} else
{
if (listFile[i].getName().endsWith(pattern))
{
System.out.println(listFile[i].getPath());
}
}
}
}
return pattern;
}
}
The file that I want the program to search ends with a .raw extension and I want the program to search for the file in the detected removable storage (e.g. F:). How do I link these 2 codes together? If possible I would like an example of codes to link them. I got the codes for FileSearch.java from http://rosettacode.org/wiki/Walk_a_directory/Recursively#Java
Heres how I would do it, however I would also make the methods USBDetect and find static, they both dont seem to have any objects their referencing in their parent class. Also make USBDetect return a File instead of a String
public static void main(String [] args) {
// look for the drive
String drive = (new DetectDrive()).USBDetect();
// if it found a drive (null or empty string says no)
if(drive != null && !drive.isEmpty()) {
// look for a file in that drive
FileSearch fileSearch = new FileSearch();
fileSearch.find(new File(drive+":"));
}
}
First, change USBDetect by replacing String driveLetter with File removableDrive, and return that. Then pass the value returned from USBDetect into find.
I have a file list which I want to sort and extract the top 3 last modified.
Constraint: I cannot use Java 7 due to compatibility issues on downstream apps
My current options
Solution 1
File[] files = directory.listFiles();
Arrays.sort(files, new Comparator<File>(){
public int compare(File f1, File f2)
{
return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
} });
Solution 2
public static void sortFilesDesc(File[] files) {
Arrays.sort(files, new Comparator() {
public int compare(Object o1, Object o2) {
if ((File)o1).lastModified().compareTo((File)o2).lastModified()) {
return -1;
} else if (((File) o1).lastModified() < ((File) o2).lastModified()) {
return +1;
} else {
return 0;
}
}
});
}
Problem
The above two solution takes more time to execute & memory. My file list consists of some 300 tar files with 200MB size each. so it is consuming more time & memory.
Is there is any way to efficiently handle this?
Every compare operation uses a file object which is of high memory is there is any way to release the memory and handle this effectively?
You can do it much faster.
Arrays.sort(...) uses "quick sort", which takes ~ n * ln(n) operations.
This example takes only one iteration trough the whole array, which is ~ n operations.
public static void sortFilesDesc(File[] files) {
File firstMostRecent = null;
File secondMostRecent = null;
File thirdMostRecent = null;
for (File file : files) {
if ((firstMostRecent == null)
|| (firstMostRecent.lastModified() < file.lastModified())) {
thirdMostRecent = secondMostRecent;
secondMostRecent = firstMostRecent;
firstMostRecent = file;
} else if ((secondMostRecent == null)
|| (secondMostRecent.lastModified() < file.lastModified())) {
thirdMostRecent = secondMostRecent;
secondMostRecent = file;
} else if ((thirdMostRecent == null)
|| (thirdMostRecent.lastModified() < file.lastModified())) {
thirdMostRecent = file;
}
}
}
On small numbers of files you won't see much difference, but even for tens of files the difference will be significant, for bigger numbers - dramatic.
The code to check the algorithm (please put in a correct files structure):
package com.hk.basicjava.clasload.tests2;
import java.io.File;
import java.util.Date;
class MyFile extends File {
private long time = 0;
public MyFile(String name, long timeMills) {
super(name);
time = timeMills;
}
#Override
public long lastModified() {
return time;
}
}
public class Files {
/**
* #param args
*/
public static void main(String[] args) {
File[] files = new File[5];
files[0] = new MyFile("File1", new Date(2013,1,15, 7,0).getTime());
files[1] = new MyFile("File2", new Date(2013,1,15, 7,40).getTime());
files[2] = new MyFile("File3", new Date(2013,1,15, 5,0).getTime());
files[3] = new MyFile("File4", new Date(2013,1,15, 10,0).getTime());
files[4] = new MyFile("File5", new Date(2013,1,15, 4,0).getTime());
sortFilesDesc(files);
}
public static void sortFilesDesc(File[] files) {
File firstMostRecent = null;
File secondMostRecent = null;
File thirdMostRecent = null;
for (File file : files) {
if ((firstMostRecent == null)
|| (firstMostRecent.lastModified() < file.lastModified())) {
thirdMostRecent = secondMostRecent;
secondMostRecent = firstMostRecent;
firstMostRecent = file;
} else if ((secondMostRecent == null)
|| (secondMostRecent.lastModified() < file.lastModified())) {
thirdMostRecent = secondMostRecent;
secondMostRecent = file;
} else if ((thirdMostRecent == null)
|| (thirdMostRecent.lastModified() < file.lastModified())) {
thirdMostRecent = file;
}
}
System.out.println("firstMostRecent : " + firstMostRecent.getName());
System.out.println("secondMostRecent : " + secondMostRecent.getName());
System.out.println("thirdMostRecent : " + thirdMostRecent.getName());
}
}
You have to check the lastModified of every file, you cannot change that. What you don't need to do is to sort all the elements just to get the top 3. If you can use Guava, you could use Ordering.greatestOf (which uses a good algorithm):
Ordering<File> ordering = Ordering.from( new Comparator(){
public int compare(File f1, File f2)
{
return Long.valueOf(f1.lastModified()).compareTo(f2.lastModified());
});
List<File> max3 = ordering.greatestOf(Arrays.asList(directory.listFiles()), 3);
I am for Solution 1, with some improvements
Arrays.sort(files, new Comparator<File>() {
public int compare(File f1, File f2) {
long d1 = f1.lastModified();
long d2 = f2.lastModified();
return d1 > d2 ? 1 : d1 < d2 ? -1 : 0;
}
});
to avoid unnecessary objects creation because of Long.valueOf(long).
File does not hold / read any file data but only the file path, there is no performance / memory issue with it. The only time consuming operation here is reading modification time from file system which cannot be avoided.
Your problem is that retrieving the last modified date is a relatively expensive operation, because it involves operating system logic. So if you don't mind to get the latest up-to-date values, you could wrap your files in a comparable class.
public class LastModifiedFile implements Comparable<LastModifiedFile> {
private final File file;
private final Date lastModified;
public LastModifiedFile(File file) {
this.file = file;
lastModified = file.lastModified();
}
public int compareTo(LastModifiedFile other) {
return lastModified.compareTo(other.lastModified);
}
}
Note that a changing last modified date during your sorting will result in undefined behavior for many sorting algorithms. Java 7s Tim Sort implementation will throw an exception, if a last modified date changes and therefore comparisons result in different values.