Construction fichiers m3u avec Apache Commons
Cet article va présenter comment effectuer reconstruire les fichiers m3u dans une arborescence de fichier mp3. Ce programme a été motivé suite à des fichiers corrompus dans une arborescence existante.
Tout le code présenté est disponible ici : http://www.jouvinio.net/svn/study/trunk/apacheCommons
Sommaire
Votre avis
Nobody voted on this yet
|
|
Objectif
L'arborescence est de parcourir une arborescence et à chaque fois qu'un fichier m3u est trouvé, celui-ci est reconstruit en injectant la liste des fichiers mp3 se trouvant dans le même répertoire, triés par ordre alphabétique en ignorant la casse.
Utilitaires
Une seule instance de Transformer est mise en place afin d'extraire le nom des fichiers depuis les instances de File
. A première vue, ceci n'est pas nécessaire, mais elle sera très utile lors de l'exécution, au moment de parcourir les fichiers. Le code est très simple et effectue uniquement l'extraction du nom du fichier lors de la transformation.
package fr.ejn.tutorial.apache.commons.tool.mp3.transformer;
import org.apache.commons.collections4.Transformer;
import java.io.File;
/**
* Transformer instance on File instance and return the file name.
*
* <p>
* Not null safe.
* </p>
*
* @author Etienne Jouvin
*
*/
public final class FileNameTransformer implements Transformer<File, String> {
/**
* Default instance.
*/
public static final FileNameTransformer INSTANCE = new FileNameTransformer();
/**
* Private constructor.
*/
private FileNameTransformer() {
}
/** {@inheritDoc} */
@Override
public String transform(File input) {
return input.getName();
}
}
Exécution
La classe d'exécution va permettre d'effectuer simplement le traitement. Le parcours de l'arborescence est facilité en étendant la classe DirectoryWalker
. Celle-ci permet de spécifier des filtres sur les répertoires parcourus, ainsi que les fichiers listés.
Pour cet exemple, tous les répertoires sont parcourus et seul les fichiers avec l'extension m3u
sont pris en compte.
Lors du traitement de chaque fichier, par conséquent les fichiers m3u
, tous les fichiers avec l'extension mp3
du même répertoire sont récupérés et triés par ordre alphabétique dans une liste. Cette liste est ensuite utilisée pour écrire dans le fichier m3u
l'ensemble des noms de fichiers.
Malgré toutes ces manipulations, le code mis en place est très simple.
package fr.ejn.tutorial.apache.commons.tool.mp3;
import fr.ejn.tutorial.apache.commons.tool.mp3.transformer.FileNameTransformer;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.io.DirectoryWalker;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.comparator.NameFileComparator;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Tutorial class used to correct existing m3u file in folders, using tools from Apache Commons.
* <ul>
* <li>DirectoryWalker to walk into a folder hierarchy;</li>
* <li>IterableUtils.toList to convert iterator into a list;</li>
* <li>CollectionUtils.collect to transform a list</li>
* </ul>
*
* <p>
* Walk into a folder hierarchy. When a folder contains a m3u file, read all mp3 files in that
* folder Sort according the file name. And then write the listing into the m3u file.
* </p>
*
* @author Etienne Jouvin
*
*/
public class FixM3u extends DirectoryWalker<String> {
private static final Logger LOGGER = LoggerFactory.getLogger(FixM3u.class);
/**
* Default constructor, specify :
* <ul>
* <li>directoryFilter with TrueFileFilter.TRUE, all folders are valid;
* <li>fileFilter with instance of WildcardFileFilter, to stop on m3u file;
* <li>depthLimit to -1.
* </ul>
*/
public FixM3u() {
super(TrueFileFilter.TRUE, new WildcardFileFilter("*.m3u", IOCase.INSENSITIVE), -1);
}
/**
* Start method to run the tool.
*
* @param path Path to explore.
* @throws IOException IO Exception.
*/
public void fixFile(String path) throws IOException {
List<String> res = new ArrayList<>();
File folder = new File(path);
walk(folder, res);
}
/** {@inheritDoc} */
@Override
protected void handleFile(File file, int depth, Collection<String> results) throws IOException {
File parentFolder = file.getParentFile();
List<File> mp3s = IterableUtils
.toList(FileUtils.listFiles(parentFolder, new String[] { "mp3" }, false));
Collections.sort(mp3s, NameFileComparator.NAME_INSENSITIVE_COMPARATOR);
Collection<String> toWrite = CollectionUtils.collect(mp3s, FileNameTransformer.INSTANCE);
try {
FileUtils.writeLines(file, "ISO-8859-1", toWrite);
} catch (IOException ioException) {
LOGGER.error("Failed to write file " + file, ioException);
throw new CancelException(file, depth);
}
}
}
Dans le constructeur par défaut, l'instance TrueFileFilter.TRUE
est utilisé pour filtrer les répertoires. Celui-ci est totalement permissif. Le second argument permet de spécifier le filtre sur les fihciers pris en compte. L'instance WildcardFileFilter
est utilisé afin de spécifier le pattern *.m3u
permettant de filtrer sur l'extension m3u
. Le troisième argument -1
permet de lever la restriction sur le niveau de profondeur de l'arborescence.
La fonction fixFile
est le seul code réellement spécifique. Il permet de déclencher le parcours de l'arborescence à partir d'une emplacement souhaité. Une instance de List
est requise pour l'exécution, même si celle-ci ne sera pas utilisée.
Puis, la méthode handleFile
est exécutée pour chacun des fichiers (et non pas des répertoires) parcourus. En entrant dans cette méthode, les fichiers seront ceux avec l'extension m3u
. Le répertoire parent est alors récupéré et la liste des fichiers mp3 est construite. Il est nécesaire de construire une liste, car c'est l'interface qui est acceptée ensuite par la fonction sort
de la classe Collection
.
List<File> mp3s = IterableUtils
.toList(FileUtils.listFiles(parentFolder, new String[] { "mp3" }, false));
Collections.sort(mp3s, NameFileComparator.NAME_INSENSITIVE_COMPARATOR);
A noter, l'utilisation de IterableUtils.toList
qui va permettre de transformer la collection retournée en liste.
Le tri est effectué à l'aide du comparateur disponible NameFileComparator.NAME_INSENSITIVE_COMPARATOR
. Il n'y a donc rien à faire.
Après cette exécution, la liste contient l'ensemble des fichiers mp3
du répertoire, triés selon le nom. C'est sur cette liste que la transformation sera exécutée pour extraire à partir des instances File
le nom du fichier.
Enfin, l'écriture du fichier est réalisée simplement par la fonction writeLines
de la classe FileUtils
qui permet d'écrire dans un fichier tous les élements d'une collection en tant que ligne.
Le test unitaire FixM3uTest
permet de valider le fonctionnement.