web-dev-qa-db-fra.com

Comment trier les noms de fichiers par ordre croissant?

J'ai un ensemble de fichiers dans un dossier, et tous commençant par un nom similaire, sauf un. Voici un exemple:

Coordinate.txt
Spectrum_1.txt
Spectrum_2.txt
Spectrum_3.txt
.
.
.
Spectrum_11235

Je peux lister tous les fichiers du dossier spécifié, mais la liste n'est pas dans un ordre croissant du numéro de spectre. Exemple: j'obtiens le résultat suivant lorsque le programme est exécuté:

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

Mais cet ordre n'est pas correct. Il doit y avoir un fichier Spectrum_1000.txt après Spectrum_999.txt. Quelqu'un peut-il aider? Voici le code:

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

            }   
        }
    }
16
novicegeek

Ce que vous demandez, c'est un tri numérique. Vous devez implémenter un Comparateur et le passer à la méthode Arrays # sort . Dans la méthode de comparaison, vous devez extraire le nombre de chaque nom de fichier et comparer les nombres.

La raison pour laquelle vous obtenez la sortie que vous obtenez maintenant est que le tri se produit alphanumérique

Voici une façon très simple de le faire. Ce code utilise une simple opération String- pour extraire les nombres. Cela fonctionne si vous connaissez le format du nom de fichier, dans votre cas Spectrum_<number>.txt. Une meilleure façon de faire l'extraction est d'utiliser expression régulière .

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

Sortie

Spectrum_1.txt
Spectrum_2.txt
Spectrum_7.txt
Spectrum_14.txt
Spectrum_999.txt
Spectrum_1000.txt
Spectrum_9990.txt
Spectrum_9991.txt
29
A4L

réponse actuellement acceptée ne le fait que pour les suffixes numériques des fichiers qui sont toujours appelés du même nom (c'est-à-dire en ignorant le préfixe).

ne solution beaucoup plus générique, sur laquelle j'ai blogué ici , fonctionne avec n'importe quel nom de fichier, divisant les noms en segments et ordonnant les segments numériquement (si les deux segments sont des nombres) ou lexicographiquement, sinon. Idée inspirée de cette réponse :

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

Cela peut également gérer la version avec des sous-versions, par exemple des choses comme version-1.2.3.txt

4
Lukas Eder

La classe NameFileComparator disponible dans Commons IO bibliothèque qui a une fonction pour trier le tableau de fichiers par nom, date de dernière modification, taille et bien d'autres. Les fichiers peuvent être triés dans l'ordre croissant et décroissant , avec sensibilité à la casse ou insensibilité à la casse.

Importer:

org.Apache.commons.io.comparator.NameFileComparator

Code:

File directory = new File(".");
File[] files = directory.listFiles();
Arrays.sort(files, NameFileComparator.NAME_COMPARATOR)
3

Vous pouvez trouver une solution à votre problème dans le commentaire ci-dessus, mais en tenant compte du fait que seul le lien a été publié, je donne le code de ce site. Fonctionne très bien.

  1. Vous devez créer votre propre AlphanumericalComparator.

     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. Triez vos fichiers en fonction de cette classe.

     File[] listOfFiles = rootFolder.listFiles();
     Arrays.sort(listOfFiles, new AlphanumFileComparator() );
     ...to sth with your files.

J'espère que cela aide. Cela a fonctionné pour moi, comme un charme.

Solution de: http://www.davekoelle.com/files/AlphanumComparator.Javaici

2
deyvw

Utilisez simplement:

  1. Pour croissant: Collections.sort (Liste)

  2. Pour décroissant: Collections.sort (List, Collections.reverseOrder ())

2
Somil Aseeja
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;
    }
});

assurez-vous de gérer les fichiers qui n'ont pas _ dans le nom

1
kdureidy