Многопоточная загрузка геометрии с помощью GeoTools

Привет, сообщество StackOverflow, в настоящее время я пытаюсь написать небольшой инструмент, который считывает геометрию шейп-файлов (мультиполигоны/многоугольники) и записывает их WKT-представления в текстовый файл. Для этого я использую GeoTools, и мне удалось заставить его работать нормально, из-за того, что я конвертирую файлы с примерно 5000000 полигонов / мультиполигонов, это занимает довольно много времени.

Итак, мой вопрос:

Можно ли прикрутить загрузку/запись файла? Поскольку я использую SimpleFeatureIterator, я не понял, как реализовать многопоточность.

Есть ли способ сделать это? Или кто-нибудь знает, как получить геометрию шейп-файлов без использования итератора?

Это мой код:

Этот метод просто устанавливает File Chooser и запускает поток для каждого выбранного файла.

protected static void printGeometriesToFile() {
    JFileChooser chooser = new JFileChooser();
    FileNameExtensionFilter filter = new FileNameExtensionFilter(
            "shape-files", "shp");
    chooser.setFileFilter(filter);
    chooser.setDialogTitle("Choose the file to be converted.");
    chooser.setMultiSelectionEnabled(true);
    File[] files = null;

    int returnVal = chooser.showOpenDialog(null);
    if (returnVal == JFileChooser.APPROVE_OPTION) {
        files = chooser.getSelectedFiles();
    }

    for (int i = 0; i < files.length; i++) {
        MultiThreadWriter writer = new MultiThreadWriter(files[i]);
        writer.start();
    }
}

Класс для многопоточности:

class MultiThreadWriter extends Thread {
    private File threadFile;

    MultiThreadWriter(File file) {
        threadFile = file;
        System.out.println("Starting Thread for " + file.getName());
    }

    public void run() {
        try {
            File outputFolder = new File(threadFile.getAbsolutePath() + ".txt");
            FileOutputStream fos = new FileOutputStream(outputFolder);
            System.out.println("Now writing data to file: " + outputFolder.getName());

            FileDataStore store = FileDataStoreFinder.getDataStore(threadFile);
            SimpleFeatureSource featureSource = store.getFeatureSource();

            SimpleFeatureCollection featureCollection = featureSource.getFeatures();
            SimpleFeatureIterator featureIterator = featureCollection.features();

            int pos = 0;

            while (featureIterator.hasNext()) {
                fos.write((geometryToByteArray((Polygonal) featureIterator.next().getAttribute("the_geom"))));

                pos++;
                System.out.println("The file " + threadFile.getName() + "'s current positon is: " + pos);
            }

            fos.close();

            System.out.println("Finished writing.");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Это всего лишь вспомогательная функция, которая преобразует мультиполигоны в полигоны и возвращает их WKT-представление со знаком «|». как разделитель.

private byte[] geometryToByteArray(Polygonal polygonal) {

    List<Polygon> polygonList;

    String polygonString = "";

    if (polygonal instanceof MultiPolygon) {
        polygonList = GeometrieUtils.convertMultiPolygonToPolygonList((MultiPolygon) polygonal);
     //The method above just converts a MultiPolygon into a list of Polygons
    } else {
        polygonList = new ArrayList<>(1);
        polygonList.add((Polygon) polygonal);
    }

    for (int i = 0; i < polygonList.size(); i++) {
        polygonString = polygonString + polygonList.get(i).toString() + "|";
    }

    return polygonString.getBytes();
}

}

Я знаю, что мой код не красивый и не хороший. Я только начал изучать Java и надеюсь, что скоро станет лучше.

искренне

я понятия не имею :)


person Ihavenoclue    schedule 09.02.2018    source источник
comment
Реальный вопрос: зачем вам текстовый файл из 5000000 полигонов wkt? Использование базы данных, вероятно, было бы лучшей идеей.   -  person Ian Turton    schedule 10.02.2018


Ответы (2)


  1. Вам не нужно создавать новый поток для каждого файла, потому что создание нового потока является дорогостоящей операцией. Вместо этого вы можете позволить MultiThreadWriter реализовать Runnable и использовать ThreadPoolExecuter для управления всеми потоками.

    MultiThreadWriter

    public class MultiThreadWriter implements Runnable {
        @Override
        public void run() {
            //
        }
    }
    

    Создайте пул потоков, соответствующий вашим процессорам времени выполнения.

    ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    
    for (int i = 0; i < files.length; i++) {
        MultiThreadWriter writer = new MultiThreadWriter(files[i]);
        service.submit(writer);
    }
    
  2. Вы можете использовать BufferedWriter вместо OutputStream, это более эффективно, когда вы повторяете небольшие частей.

    File outputFolder = new File(threadFile.getAbsolutePath() + ".txt");
    FileOutputStream fos = new FileOutputStream(outputFolder);
    BufferedWriter writer = new BufferedWriter(fos);
    
person xingbin    schedule 10.02.2018

Я бы предпочел читать содержимое файлов в виде списка объектов, затем разбивать список на подсписки, а затем создавать поток для каждого списка, например:

int nbrThreads = 10;

ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(nbrThreads);

int count = myObjectsList != null ? myObjectsList.size() / nbrThreads : 0;

List<List<MyObject>> resultlists = choppeList(myObjectsList, count > 0 ? count : 1);

try
{
    for (List<MyObject> list : resultlists)
    {
        // TODO : create your thread and passe the list of objects   
    }

    executor.shutdown();

    executor.awaitTermination(30, TimeUnit.MINUTESS); // chose time of termination
}
catch (Exception e)
{
    LOG.error("Problem launching threads", e);
}

Метод ChoppeList может быть таким:

public <T> List<List<T>> choppeList(final List<T> list, final int L)
{
    final List<List<T>> parts = new ArrayList<List<T>>();
    final int N = list.size();
    for (int i = 0; i < N; i += L)
    {
        parts.add(new ArrayList<T>(list.subList(i, Math.min(N, i + L))));
    }
    return parts;
}
person Nomade    schedule 09.02.2018