gpt4 book ai didi

Java 文件列表的顺序与 Window 资源管理器相同

转载 作者:行者123 更新时间:2023-12-02 19:41:16 26 4
gpt4 key购买 nike

我使用下面的代码来获取文件列表排序:(如窗口资源管理器)

    package com.codnix.quickpdfgenerator.testing;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FileListOrder {
public static void main(String args[]) {
//huge test data set ;)

File folder = new File("C:\\Users\\Codnix\\Desktop\\Test Sequence");
File[] listOfFiles = folder.listFiles();
List<File> filenames = Arrays.asList(listOfFiles);

//adaptor for comparing files
Collections.sort(filenames, new Comparator<File>() {
private final Comparator<String> NATURAL_SORT = new WindowsExplorerComparator();

@Override
public int compare(File o1, File o2) {;
return NATURAL_SORT.compare(o1.getName(), o2.getName());
}
});

for (File f : filenames) {
System.out.println(f);
}
}

public static class WindowsExplorerComparator implements Comparator<String> {

private static final Pattern splitPattern = Pattern.compile("\\d+|\\.|\\s");

@Override
public int compare(String str1, String str2) {
Iterator<String> i1 = splitStringPreserveDelimiter(str1).iterator();
Iterator<String> i2 = splitStringPreserveDelimiter(str2).iterator();
while (true) {
//Til here all is equal.
if (!i1.hasNext() && !i2.hasNext()) {
return 0;
}
//first has no more parts -> comes first
if (!i1.hasNext() && i2.hasNext()) {
return -1;
}
//first has more parts than i2 -> comes after
if (i1.hasNext() && !i2.hasNext()) {
return 1;
}

String data1 = i1.next();
String data2 = i2.next();
int result;
try {
//If both datas are numbers, then compare numbers
result = Long.compare(Long.valueOf(data1), Long.valueOf(data2));
//If numbers are equal than longer comes first
if (result == 0) {
result = -Integer.compare(data1.length(), data2.length());
}
} catch (NumberFormatException ex) {
//compare text case insensitive
result = data1.compareToIgnoreCase(data2);
}

if (result != 0) {
return result;
}
}
}

private List<String> splitStringPreserveDelimiter(String str) {
Matcher matcher = splitPattern.matcher(str);
List<String> list = new ArrayList<String>();
int pos = 0;
while (matcher.find()) {
list.add(str.substring(pos, matcher.start()));
list.add(matcher.group());
pos = matcher.end();
}
list.add(str.substring(pos));
return list;
}
}
}

BUT,运行程序时输出:

C:\Users\Codnix\Desktop\Test Sequence\1 test -12.jpg
C:\Users\Codnix\Desktop\Test Sequence\1 test --11.jpg
C:\Users\Codnix\Desktop\Test Sequence\1 test ---10.jpg

预期输出(如窗口资源管理器):

C:\Users\Codnix\Desktop\Test Sequence\1 test ---10.jpg
C:\Users\Codnix\Desktop\Test Sequence\1 test --11.jpg
C:\Users\Codnix\Desktop\Test Sequence\1 test -12.jpg

in window explorer it showing like this(sort by name)

如何获取这样的文件列表?

已更新

@jannis 提供的已实现解决方案

And here its output

before

1 test ---10.jpg
1 test --11.jpg
1 test -12.jpg
1.jpg
10.jpg
2.jpg

After (output)

1.jpg
1 test ---10.jpg
1 test --11.jpg
1 test -12.jpg
2.jpg
10.jpg

预期

enter image description here

最佳答案

在 Windows 中按名称排序非常棘手,而且比您的实现复杂得多。它也是可配置的并且依赖于版本。

注意:我为本文接下来的内容创建了一个演示。 Check it out on GitHub .

使用StrCmpLogicalWComparator function对文件名进行排序

根据一些(例如 here )Windows 使用 StrCmpLogicalW用于按名称对文件进行排序。

您可以尝试使用 JNA 调用此系统函数来实现比较器(不要忘记在项目中包含 JNA library):

比较器:

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 资源管理器对文件进行排序的方式是可配置的。您可以更改文件名中数字的处理方式并切换所谓的“数字排序”。您可以阅读如何配置此here 。文档中解释的数字排序:

Treat digits as numbers during sorting, for example, sort "2" before "10".

-- https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringex#SORT_DIGITSASNUMBERS

启用数字排序后,结果为:

file names sorted with numerical sorting enabled

而禁用数字排序后,它看起来像这样:

file names sorted with numerical sorting disabled

这让我认为 Windows 资源管理器实际上使用 CompareStringEx function用于排序,可以对其进行参数化以启用此功能。

使用CompareStringEx function对文件名进行排序

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

数字排序比较器:

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

非数字排序比较器:

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

引用文献

关于Java 文件列表的顺序与 Window 资源管理器相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60092486/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com