【问题标题】:Sorting an array of filenames containing strings with numbers对包含数字字符串的文件名数组进行排序
【发布时间】:2016-07-02 15:02:18
【问题描述】:

对于我的项目,我需要从 FTP 服务器下载一个 zip 文件,该服务器每年大约发布 13 次新的 zip。我需要按照服务器的命名约定下载最新的文件:
Prefix + release number (one or two digits) + year (two digits) + suffix + ".zip"

例如: ALFP1016F.zip

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

  1. 最近一年。当然,不应将 99 年视为最近的一年。
  2. 最新版本号

例如,如果我有这个文件名列表 (full server directory):

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[]) 方法时做了一次悲惨的尝试,但结果却是一团糟,不值得在这里发布。

如何对这个数组进行排序并按照我的优先顺序有效地返回最近的文件?

【问题讨论】:

  • 您可以使用Regular Expressions with Capturing Groups 隔离文件名的重要部分,然后使用它们来查找最新版本(无需实际排序)。如果这太复杂了,那么使用多个substring() 来做同样的事情。

标签: java android arrays algorithm sorting


【解决方案1】:

如果你使用 Java8,你可以这样做:

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

版本比较器基于从文件名中提取数字并进行比较

【讨论】:

  • 这假设版本号是个位数,而 brso05 答案不是
  • @BalajiKrishnan 是的,需要自定义比较器才能正确排序数字。我将把它留给 OP,因为 brso05 已经给出了提示
  • Stream.max 会比链接sortedfindFirst 更有效并且可能更清晰。此外,如果您不打算提供一个有效的比较器,您可能应该写类似appropriateComparator 而不是Comparator.reverseOrder() 这样至少很明显Comparator.reverseOrder() 不起作用。
【解决方案2】:

我没有对此进行测试,但我认为它应该可以工作。

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】:

我会建议这种方法:

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

        【讨论】:

          猜你喜欢
          • 2020-02-18
          • 2019-05-26
          • 2011-03-07
          • 1970-01-01
          • 2011-07-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多