Сортировка по имени в Windows сложна и намного сложнее, чем ваша реализация. Он также настраивается и зависит от версии.
ПРИМЕЧАНИЕ. Я создал демонстрационную версию, описанную в этом посте. Проверьте это на GitHub .
Согласно некоторым (например, здесь ) Windows использует StrCmpLogicalW для сортировки файлов по имени.
Вы можете попробовать реализовать свой компаратор, вызвав эту системную функцию с помощью JNA (не забудьте включить JNA библиотека в вашем проекте):
Компаратор:
public class StrCmpLogicalWComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return Shlwapi.INSTANCE.StrCmpLogicalW(
new WString(o1), new WString(o2));
}
}
JNA-часть:
import com.sun.jna.WString;
import com.sun.jna.win32.StdCallLibrary;
public interface Shlwapi extends StdCallLibrary {
Shlwapi INSTANCE = Native.load("Shlwapi", Shlwapi.class);
int StrCmpLogicalW(WString psz1, WString psz2);
}
Обработка имен файлов, содержащих цифры
Ранее я упоминал, что способ сортировки файлов Windows Explorer настраивается. Вы можете изменить способ обработки чисел в именах файлов и включить так называемую «числовую сортировку». Вы можете прочитать, как настроить здесь . Числовая сортировка, как описано в документации:
При сортировке обрабатывать цифры как числа, например, сортировать «2» перед «10».
- https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringex#SORT_DIGITSASNUMBERS
При включенной числовой сортировке результат будет:
, тогда как при отключенной числовой сортировке это выглядит так :
Это заставляет меня думать, что Windows Explorer фактически использует функцию CompareStringEx для сортировки, которая может быть параметризованный для включения этой функции.
JNA-часть:
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.win32.StdCallLibrary;
public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = Native.load("Kernel32", Kernel32.class);
WString INVARIANT_LOCALE = new WString("");
int CompareStringEx(WString lpLocaleName,
int dwCmpFlags,
WString lpString1,
int cchCount1,
WString lpString2,
int cchCount2,
Pointer lpVersionInformation,
Pointer lpReserved,
int lParam);
default int CompareStringEx(int dwCmpFlags,
String str1,
String str2) {
return Kernel32.INSTANCE
.CompareStringEx(
INVARIANT_LOCALE,
dwCmpFlags,
new WString(str1),
str1.length(),
new WString(str2),
str2.length(),
Pointer.NULL,
Pointer.NULL,
0);
}
}
Numeri c sort компаратор:
public class CompareStringExNumericComparator implements Comparator<String> {
private static int SORT_DIGITSASNUMBERS = 0x00000008;
@Override
public int compare(String o1, String o2) {
int compareStringExComparisonResult =
Kernel32.INSTANCE.CompareStringEx(SORT_DIGITSASNUMBERS, o1, o2);
// CompareStringEx returns 1, 2, 3 respectively instead of -1, 0, 1
return compareStringExComparisonResult - 2;
}
}
без нумерации c сортировщик сравнения:
public class CompareStringExNonNumericComparator implements Comparator<String> {
private static String INVARIANT_LOCALE = "";
private static int NO_OPTIONS = 0;
@Override
public int compare(String o1, String o2) {
int compareStringExComparisonResult =
Kernel32.INSTANCE.CompareStringEx(NO_OPTIONS, o1, o2);
// CompareStringEx returns 1, 2, 3 respectively instead of -1, 0, 1
return compareStringExComparisonResult - 2;
}
}
ссылки