Как сортировать имена файлов в порядке возрастания?
У меня есть набор файлов в папке, и все они начинаются с аналогичного имени, кроме одного. Вот пример:
Coordinate.txt
Spectrum_1.txt
Spectrum_2.txt
Spectrum_3.txt
.
.
.
Spectrum_11235
Я могу перечислить все файлы из указанной папки, но список не находится в порядке возрастания номера спектра. Пример: При выполнении программы получается следующий результат:
Spectrum_999.txt
Spectrum_9990.txt
Spectrum_9991.txt
Spectrum_9992.txt
Spectrum_9993.txt
Spectrum_9994.txt
Spectrum_9995.txt
Spectrum_9996.txt
Spectrum_9997.txt
Spectrum_9998.txt
Spectrum_9999.txt
Но этот порядок неверен. Должен быть файл Spectrum_1000.txt после Spectrum_999.txt. Может ли кто-нибудь помочь? Вот код:
import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class FileInput {
public void userInput()
{
Scanner scanner = new Scanner( System.in );
System.out.println("Enter the file path: ");
String dirPath = scanner.nextLine(); // Takes the directory path as the user input
File folder = new File(dirPath);
if(folder.isDirectory())
{
File[] fileList = folder.listFiles();
Arrays.sort(fileList);
System.out.println("\nTotal number of items present in the directory: " + fileList.length );
// Lists only files since we have applied file filter
for(File file:fileList)
{
System.out.println(file.getName());
}
// Creating a filter to return only files.
FileFilter fileFilter = new FileFilter()
{
@Override
public boolean accept(File file) {
return !file.isDirectory();
}
};
fileList = folder.listFiles(fileFilter);
// Sort files by name
Arrays.sort(fileList, new Comparator()
{
@Override
public int compare(Object f1, Object f2) {
return ((File) f1).getName().compareTo(((File) f2).getName());
}
});
//Prints the files in file name ascending order
for(File file:fileList)
{
System.out.println(file.getName());
}
}
}
}
Ответы
Ответ 1
То, что вы просите, это числовая сортировка. Вам необходимо внедрить Comparator и передать его в метод Arrays # sort. В методе сравнения вам нужно извлечь число из каждого имени файла, а затем сравнить числа.
Причина, по которой вы получаете вывод, который вы получаете сейчас, заключается в том, что сортировка происходит буквенно-цифровым способом
Здесь очень простой способ сделать это. Этот код использует простой String
-operation для извлечения чисел. Это работает, если вы знаете формат имени файла, в вашем случае Spectrum_<number>.txt
. Лучший способ сделать это - использовать регулярное выражение.
public class FileNameNumericSort {
private final static File[] files = {
new File("Spectrum_1.txt"),
new File("Spectrum_14.txt"),
new File("Spectrum_2.txt"),
new File("Spectrum_7.txt"),
new File("Spectrum_1000.txt"),
new File("Spectrum_999.txt"),
new File("Spectrum_9990.txt"),
new File("Spectrum_9991.txt"),
};
@Test
public void sortByNumber() {
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
int n1 = extractNumber(o1.getName());
int n2 = extractNumber(o2.getName());
return n1 - n2;
}
private int extractNumber(String name) {
int i = 0;
try {
int s = name.indexOf('_')+1;
int e = name.lastIndexOf('.');
String number = name.substring(s, e);
i = Integer.parseInt(number);
} catch(Exception e) {
i = 0; // if filename does not match the format
// then default to 0
}
return i;
}
});
for(File f : files) {
System.out.println(f.getName());
}
}
}
Выход
Spectrum_1.txt
Spectrum_2.txt
Spectrum_7.txt
Spectrum_14.txt
Spectrum_999.txt
Spectrum_1000.txt
Spectrum_9990.txt
Spectrum_9991.txt
Ответ 2
в настоящее время принятый ответ делает это только для числовых суффиксов файлов, которые всегда называются одним и тем же именем (т.е. игнорируя префикс).
Гораздо более общее решение, о котором я писал здесь, работает с любым именем файла, разделяя имена по сегментам и упорядочивая сегменты по номерам (если оба сегмента являются числами) или лексикографически, в противном случае. Идея, вдохновленная этим ответом:
public final class FilenameComparator implements Comparator<String> {
private static final Pattern NUMBERS =
Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
@Override public final int compare(String o1, String o2) {
// Optional "NULLS LAST" semantics:
if (o1 == null || o2 == null)
return o1 == null ? o2 == null ? 0 : -1 : 1;
// Splitting both input strings by the above patterns
String[] split1 = NUMBERS.split(o1);
String[] split2 = NUMBERS.split(o2);
for (int i = 0; i < Math.min(split1.length, split2.length); i++) {
char c1 = split1[i].charAt(0);
char c2 = split2[i].charAt(0);
int cmp = 0;
// If both segments start with a digit, sort them numerically using
// BigInteger to stay safe
if (c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9')
cmp = new BigInteger(split1[i]).compareTo(new BigInteger(split2[i]));
// If we haven't sorted numerically before, or if numeric sorting yielded
// equality (e.g 007 and 7) then sort lexicographically
if (cmp == 0)
cmp = split1[i].compareTo(split2[i]);
// Abort once some prefix has unequal ordering
if (cmp != 0)
return cmp;
}
// If we reach this, then both strings have equally ordered prefixes, but
// maybe one string is longer than the other (i.e. has more segments)
return split1.length - split2.length;
}
}
Это также может обрабатывать версию с подрывными действиями, например, такие вещи, как version-1.2.3.txt
Ответ 3
Класс NameFileComparator
доступен в библиотеке Commons IO, которая имеет функцию сортировки массива файлов по имени, последней измененной дате, размеру и многим другим. Файлы можно сортировать в порядке возрастания и убывания, с чувствительностью к регистру или чувствительностью к регистру.
Импорт:
org.apache.commons.io.comparator.NameFileComparator
Код:
File directory = new File(".");
File[] files = directory.listFiles();
Arrays.sort(files, NameFileComparator.NAME_COMPARATOR)
Ответ 4
Вы можете найти решение вашей проблемы в комментарии выше, но, учитывая, что была опубликована только ссылка, я даю код с этого сайта. Работал отлично.
Вам нужно создать свой собственный алфавитно-цифровой компаратор.
import java.io.File;
import java.util.Comparator;
public class AlphanumFileComparator implements Comparator
{
private final boolean isDigit(char ch)
{
return ch >= 48 && ch <= 57;
}
private final String getChunk(String s, int slength, int marker)
{
StringBuilder chunk = new StringBuilder();
char c = s.charAt(marker);
chunk.append(c);
marker++;
if (isDigit(c))
{
while (marker < slength)
{
c = s.charAt(marker);
if (!isDigit(c))
break;
chunk.append(c);
marker++;
}
} else
{
while (marker < slength)
{
c = s.charAt(marker);
if (isDigit(c))
break;
chunk.append(c);
marker++;
}
}
return chunk.toString();
}
public int compare(Object o1, Object o2)
{
if (!(o1 instanceof File) || !(o2 instanceof File))
{
return 0;
}
File f1 = (File)o1;
File f2 = (File)o2;
String s1 = f1.getName();
String s2 = f2.getName();
int thisMarker = 0;
int thatMarker = 0;
int s1Length = s1.length();
int s2Length = s2.length();
while (thisMarker < s1Length && thatMarker < s2Length)
{
String thisChunk = getChunk(s1, s1Length, thisMarker);
thisMarker += thisChunk.length();
String thatChunk = getChunk(s2, s2Length, thatMarker);
thatMarker += thatChunk.length();
/** If both chunks contain numeric characters, sort them numerically **/
int result = 0;
if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0)))
{
// Simple chunk comparison by length.
int thisChunkLength = thisChunk.length();
result = thisChunkLength - thatChunk.length();
// If equal, the first different number counts
if (result == 0)
{
for (int i = 0; i < thisChunkLength; i++)
{
result = thisChunk.charAt(i) - thatChunk.charAt(i);
if (result != 0)
{
return result;
}
}
}
} else
{
result = thisChunk.compareTo(thatChunk);
}
if (result != 0)
return result;
}
return s1Length - s2Length;
}
}
2. Сортируйте файлы в зависимости от этого класса.
File[] listOfFiles = rootFolder.listFiles();
Arrays.sort(listOfFiles, new AlphanumFileComparator() );
...to sth with your files.
Надеюсь, это поможет. Это сработало для меня, как шарм.
Решение от: http://www.davekoelle.com/files/AlphanumComparator.java здесь
Ответ 5
Просто используйте:
По возрастанию: Collections.sort (список)
По убыванию: Collections.sort(List, Collections.reverseOrder())
Ответ 6
Arrays.sort(fileList, new Comparator()
{
@Override
public int compare(Object f1, Object f2) {
String fileName1 = ((File) f1).getName();
String fileName2 = ((File) f1).getName();
int fileId1 = Integer.parseInt(fileName1.split("_")[1]);
int fileId2 = Integer.parseInt(fileName2.split("_")[1]);
return fileId1 - fileId2;
}
});
обязательно обрабатывайте файлы, которые не имеют _ в имени
Ответ 7
Я думаю, что все приведенные здесь ответы не идеальны, они полагаются на соглашения об именах и т.д. Подобно тому, как имя похоже на файл run1dom.txt или что-то еще, мы хотим, чтобы файлы упорядочивались в порядке возрастания так же, как они упорядочены Windows Explorer. Если это то, что вы хотите, я думаю, что этот учебник описывает идеальный подход:
http://haidermushtaq.com/the-problem-with-alphabetically-sorting-files-if-their-name-contains-a-number/
Ответ 8
вы можете использовать Collections.sort(fileList);
для сортировки arraylist.
Затем используйте
for(File file:fileList)
System.out.println(file.getName());
Collections.sort()
Ответ 9
Еще один способ сделать это, но используя силу java8
List<Path> x = Files.list(Paths.get("C:\\myPath\\Tools"))
.filter(p -> Files.exists(p))
.map(s -> s.getFileName())
.sorted()
.collect(Collectors.toList());
x.forEach(System.out::println);