对包含数字字符串的文件名数组进行排序

10

为了我的项目,我需要从FTP服务器下载一个zip文件,该服务器每年发布约13次新的zip文件。我需要按照服务器的命名约定下载最新的文件:
前缀 + 发布号(一到两位数字)+ 年份(两位数字)+ 后缀 + ".zip"

例如: ALFP1016F.zip

前缀将始终相同(ALFP),后缀为F或P(表示“完整”或“部分”;我只需要以F结尾的文件)。此外,目录中还有其他几个文件需要忽略,因为它们具有不同的前缀。然后,我需要按照以下优先顺序获取数组中的最新文件:

  1. 最近的年份。当然,“99”不应视为最近的年份。
  2. 最新的发布号

例如,如果我有以下文件名列表(完整的服务器目录):

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
你可以使用具有捕获组的正则表达式来分离文件名的重要部分,然后使用它们来查找最新版本(不需要实际排序)。如果这太复杂了,那么可以使用多个substring()来完成相同的任务。 - PM 77-1
6个回答

5
如果您使用Java8,可以执行以下操作:
String file = Arrays.stream(filenames)
                    .filter(s -> s.startsWith("ALFP") && s.endsWith("F.zip"))
                    .max(getReleaseComparator())                        
                    .orElse(null);

其中版本号比较器是基于从文件名中提取数字并进行比较的。


这里假设版本号为单个数字,而brso05的答案并没有考虑到这一点。 - Balaji Krishnan
@BalajiKrishnan 是的,需要自定义比较器才能正确排序数字。我会让OP来处理,因为brso05已经给了一个提示。 - AdamSkywalker
Stream.max比链接sortedfindFirst更高效,可能也更清晰。此外,如果您不打算提供一个可用的比较器,那么最好写成appropriateComparator而不是Comparator.reverseOrder(),这样至少可以清楚地表明Comparator.reverseOrder()无法使用。 - user2357112

3

我还没有测试过,但我认为它应该可以工作。

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

只要版本号始终是一位数字(这并不是事实),这似乎可以解决问题。 - justbourv
我在代码中添加了两行。这样就可以解决它了。 - Till
我不得不对你的代码进行了相当大的修改,但最终让它工作了。谢谢! - justbourv

2
我建议采用以下方法:

我建议采用以下方法:

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

}

2
我建议采用以下解决方案:
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";
    }

1
你可以使用正则表达式来解析出年份和版本号,例如:
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);

}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接