10

For my project I need to download a zip file from an FTP server, which releases a new zip about 13 times a year. I need to download the latest file following the server's naming convention:
Prefix + release number (one or two digits) + year (two digits) + suffix + ".zip"

for instance: ALFP1016F.zip

The prefix will always be the same (ALFP) and the suffix either F or P (stands for "full" or "partial"; I need only the files ending with suffix F). On top of that, there are several other files in the directory I need to ignore because they have different prefixes. Then, I need to get the most recent file in the array following this priority order:

  1. Most recent year. Of course '99 should not be seen as the most recent year.
  2. Most recent release number

For instance, if I have this listing of filenames (full server directory):

1stpage712.pdf
1stpage914.pdf
ALFP1015F.zip
ALFP1015P.zip
ALFP716F.zip
ALFP716P.zip
FSFP816F.zip
FSFP816P.zip

My expected output would be
ALFP716F.zip because 16 is the most recent year, and 7 the most recent release number from that year

.

Here's what I've done so far:

//necessary imports
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;

//initialize FTP client
ftpClient = new FTPClient();

try {
    //connect to server
    ftpClient.connect(server, port);
    ftpClient.login(username, password);
    ftpClient.enterLocalPassiveMode();
    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

    //list all names from server
    String[] filenames = ftpClient.listNames();

    //return expected file name
    String expectedFileName = returnMostRecent(filenames);
} catch (Exception e) { 
    e.printStackTrace(); 
} finally {
    try {
        if (ftpClient.isConnected()) {
            ftpClient.logout();
            ftpClient.disconnect();
            System.out.println("Disconnected from server");
        }
    } catch (IOException ex) { ex.printStackTrace(); }
}

I have done a miserable attempt at writing the returnMostRecent(String[]) method, but ended up with an unintelligible mess not worth being posted here.

How can I sort this array and effectively return the most recent file following my priority order?

1
  • 1
    You can use Regular Expressions with Capturing Groups to isolate the important parts of file names and then use them for finding the most recent release (no need to actually sort). If this is too involved then use multiple substring() to do the same. Commented Mar 16, 2016 at 16:05

6 Answers 6

5

If you use Java8 you can do:

String file = Arrays.stream(filenames)
                    .filter(s -> s.startsWith("ALFP") && s.endsWith("F.zip"))
                    .max(getReleaseComparator())                        
                    .orElse(null);

where release comparator is based on extracting numbers from file name and comparing them

Sign up to request clarification or add additional context in comments.

3 Comments

this assumes version number is single digit, where as brso05 answer does not
@BalajiKrishnan that's true, custom comparator is required to sort numbers correctly. I' ll leave that to OP since brso05 already gave a hint
Stream.max would be more efficient and probably clearer than chaining sorted and findFirst. Also, if you're not going to provide a working comparator, you should probably write something like appropriateComparator instead of Comparator.reverseOrder() so it's at least clear that Comparator.reverseOrder() won't work.
3

I haven't tested this but I think it should work.

private String returnMostRecent(String[] fileNames) {
   String file = null;
   double version = -1;
   for(String name : listNames)
   {
      // skip files that don't match
      if (!name.matches("ALFP[0-9]*F.zip"))
          continue;
      // get digits only
      String digits = name.replaceAll("\\D+","");
      // format digits to <year>.<version>
      String vstr = digits.substring(digits.length-2,digits.length()) + ".";
      if (digits.length() < 4)
         vstr += "0";
      vstr = digits.substring(0, digits.length()-2);
      double v = Double.parseDouble(vstr);
      if (v > version)
      {
          version = v;
          file = name;
      }
   }

   return file;
}

3 Comments

This seems to do the trick, provided that the version number is always one digit - which is not the case.
I added two lines two the code. That should take care of it.
I had to modify your code quite a bit, but finally got it to work. Thanks!
2

I will suggest this approach:

final String[] filesArr = { "1stpage712.txt", "1stpage712.pdf", "1stpage914.pdf", "ALFP1015F.zip", "ALFP1015P.zip", "ALFP716F.zip",
            "ALFP716P.zip", "FSFP816F.zip", "FSFP816P.zip" };

    // turn the array into a list.
    final List<String> filesList = new ArrayList<String>();
    // add to the list only the good candidates
    for (int i = 0; i < filesArr.length; i++) {
        if (filesArr[i].matches("ALFP\\d+F.zip")) {
            System.out.println("candidate");
            filesList.add(filesArr[i]);
        }
    }
    System.out.println(filesList);
    Collections.sort(filesList, new Comparator<String>() {

        @Override
        public int compare(String o1, String o2) {
            final SimpleDateFormat df = new SimpleDateFormat("mmyy");
            // get the date of the file
            final String dat1 = o1.substring(o1.indexOf("ALFP"), o1.indexOf("ALFP") + 3);
            final String dat2 = o2.substring(o2.indexOf("ALFP"), o2.indexOf("ALFP") + 3);
            Date date1;
            Date date2;
            try {
                date1 = df.parse(dat1);
                date2 = df.parse(dat2);

                return date1.compareTo(date2);
            } catch (final ParseException e) {
                System.out.println("Error parsing date..");
                return 0;
            }
        }
    });

    // since the sort is made by date chronologically, the 1st element is the oldest and the last element is
    // the newest
    System.out.println("The file is: " + filesList.get(filesList.size() - 1));

}

Comments

2

I will suggest this Solution :

private static String returnMostRecent(String[] fileNames)
    {
       int lastTwoDigits = Calendar.getInstance().get(Calendar.YEAR) % 100;
       int fullFileRel = 0;
       int partialFileRel = 0;
       for(String myStr : fileNames)
       {

          if(myStr.startsWith("ALFP"))
          {
              System.out.println(myStr);
             if(myStr.endsWith(""+lastTwoDigits+"F.zip"))
             {
              String temp = myStr.substring(4,myStr.length()-7);
                 System.out.println("temp : "+temp);
                 int releaseNum = Integer.parseInt(temp);
                 System.out.println("releaseNum : "+releaseNum);
                 if(releaseNum > fullFileRel)
                     fullFileRel = releaseNum;            
             }

             if(myStr.endsWith(""+lastTwoDigits+"P.zip"))
             {
                String temp = myStr.substring(4,myStr.length()-7);
                 System.out.println("temp : "+temp);
                 int releaseNum = Integer.parseInt(temp);
                 System.out.println("releaseNum : "+releaseNum);
                 if(releaseNum > fullFileRel)
                     partialFileRel = releaseNum;
             }          
          }
       }

        System.out.println("full Rel :"+fullFileRel);
        System.out.println("partial Rel :"+partialFileRel);

       if(fullFileRel > partialFileRel)
           return "ALFP"+fullFileRel+""+lastTwoDigits+"F.zip";
       else
           return "ALFP"+partialFileRel+""+lastTwoDigits+"P.zip";
    }

Comments

1

You can use regex and do something like this to parse out the year and version:

public static void main(String[] args)
{
    int year = -1;
    int version = -1;
    String test = "ALFP716F.zip";
    if(test.matches("ALFP\\d+F.zip"))
    {
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(test);
        matcher.find();
        String tempString = matcher.group(0);
        year = Integer.parseInt(tempString.substring((tempString.length() - 2)));
        version = Integer.parseInt(tempString.substring(0, (tempString.length() - 2)));
    }
    System.out.println("Year: " + year + "    Version: " + version);

}

Comments

1

Here is Java 1.5 compatible solution, AlphaNumComparator

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.