Более быстрый способ собрать в arraylist в Java - PullRequest
0 голосов
/ 02 ноября 2018

У меня есть каталог с большим количеством файлов, и я хочу отфильтровать каталог с определенным именем и сохранить его в fileList ArrayList, и он работает таким образом, но занимает много времени. Есть ли способ сделать это быстрее?

String processingDir = "C:/Users/Ferid/Desktop/20181024";
String CorrId = "00a3d321-171c-484a-ad7c-74e22ffa3625");
Path dirPath = Paths.get(processingDir);       

ArrayList<Path> fileList;

try (Stream<Path> paths = Files.walk(dirPath))
{           
    fileList = paths.filter(t -> (t.getFileName().toString().indexOf("EPX_" + 
    corrId + "_") >= 0)).collect(Collectors.toCollection(ArrayList::new));
}

Просмотр каталога в состоянии try не занимает много времени, но сбор его в fileList занимает много времени, и я не знаю, какая именно операция имеет плохую производительность или какую из них улучшить , (Это, конечно, не полный код, а соответствующие вещи)

Ответы [ 2 ]

0 голосов
/ 02 ноября 2018

От java.nio.file.Files.walk(Path) API:

Верните поток, который лениво заполнен с помощью Path, пройдя файл дерево с корнем в заданном начальном файле.

Именно поэтому у вас создается впечатление, что «просмотр каталога в состоянии try не занимает много времени».

На самом деле, реальная сделка в основном заключается на collect, и это не ошибка механизма сбора за медлительность.

0 голосов
/ 02 ноября 2018

Если сканирование файлов каждый раз происходит слишком медленно, вы можете создать индекс файлов либо при запуске, либо сохраняемый и сохраняемый при изменении файлов.

Вы можете использовать Watch Service , чтобы получать уведомления о добавлении или удалении файлов во время работы программы.

Это было бы намного быстрее для запроса, поскольку это было бы полностью в памяти. Загрузка в первый раз займет столько же времени, но может потребоваться загрузка фона, прежде чем он вам понадобится изначально.

, например

static Map<String, List<Path>> pathMap;
public static void initPathMap(String processingDir) throws IOException {
    try (Stream<Path> paths = Files.walk(Paths.get(processingDir))) {
        pathMap = paths.collect(Collectors.groupingBy(
                p -> getCorrId(p.getFileName().toString())));
    }
    pathMap.remove(""); // remove entries without a corrId.
}


private static String getCorrId(String fileName) {
    int start = fileName.indexOf("EPX_");
    if (start < 0)
        return "";
    int end = fileName.indexOf("_", start + 4);
    if (end < 0)
        return "";
    return fileName.substring(start + 4, end);
}

// later 
    String corrId = "00a3d321-171c-484a-ad7c-74e22ffa3625";
    List<Path> pathList = pathMap.get(corrId); // very fast.

Вы можете сделать этот код чище, написав следующее, однако я не ожидаю, что он будет намного быстрее.

List<Path> fileList;

try (Stream<Path> paths = Files.walk(dirPath)) {           
    String find = "EPX_" + corrId + "_"; // only calculate this once
    fileList = paths.filter(t -> t.getFileName().contains(find))
                    .collect(Collectors.toList());
}

Стоимость указана за время, необходимое для сканирования файлов каталога. Стоимость обработки имен файлов намного, намного меньше.

Использование SSD или только сканирующих каталогов, уже кэшированных в памяти, значительно ускорит это.

Один из способов проверить это - выполнить операцию более одного раза после чистой загрузки (чтобы она не кэшировалась). Количество, которое длится первый запуск, говорит о том, сколько времени было потрачено на загрузку данных с диска.

...