Сортировка массива имен файлов, содержащих строки с номерами

Для моего проекта мне нужно загрузить zip файл с FTP-сервера, который выпускает новый zip примерно 13 раз в год. Мне нужно загрузить последний файл в соответствии с соглашением об именах серверов:
Prefix + release number (one or two digits) + year (two digits) + suffix + ".zip"

например: ALFP1016F.zip

Префикс всегда будет одинаковым (ALFP) и суффикс F или P (означает "полный" или "частичный", мне нужны только файлы, заканчивающиеся суффиксом F). Кроме того, в директории, которую мне нужно игнорировать, есть несколько других файлов, потому что они имеют разные префиксы. Затем мне нужно получить самый последний файл в массиве, следующий за этим порядком приоритета:

  • Последний год. Конечно, '99 не следует рассматривать как самый последний год.
  • Самый последний номер выпуска

Например, если у меня есть этот список имен файлов (полный каталог сервера):

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

Мой ожидаемый результат будет    ALFP716F.zip , поскольку 16 - последний год, а 7 - последний номер выпуска с этого года

.

Вот что я сделал до сих пор:

//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(); }
}

Я сделал жалкую попытку написать метод returnMostRecent(String[]), но в итоге оказался непонятным беспорядок, который не стоит публиковать здесь.

Как я могу отсортировать этот массив и эффективно вернуть последний файл после моего приоритетного порядка?

Ответ 1

Я не тестировал это, но думаю, что он должен работать.

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;
}

Ответ 2

Если вы используете Java8, вы можете сделать:

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

где компаратор релиза основан на извлечении чисел из имени файла и их сравнении

Ответ 3

Я предлагаю такой подход:

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));

}

Ответ 4

Я предлагаю это решение:

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";
    }

Ответ 5

Вы можете использовать регулярное выражение и сделать что-то подобное для анализа года и версии:

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);

}

Ответ 6

Вот решение, совместимое с Java 1.5, AlphaNumComparator