【问题标题】:Multithreaded Geometry loading with GeoTools使用 GeoTools 进行多线程几何加载
【发布时间】:2018-07-20 12:06:36
【问题描述】:

嘿 StackOverflow 社区, 我目前正在尝试编写一个小工具,它读取 shapefiles 几何图形(多多边形/多边形)并将它们的 WKT 表示写入文本文件。 为此,我正在使用 GeoTools 并且我设法让它运行良好,因为我正在转换包含大约 5000000 个多边形/多多边形的文件,这需要很长时间才能完成。

所以我的问题是:

是否可以加快文件加载/写入速度? 由于我使用的是 SimpleFeatureIterator,我没有找到如何实现多线程。

有没有办法做到这一点? 或者有谁知道,如何在不使用迭代器的情况下获取 shapefile 几何图形?

这是我的代码:

此方法只是说明文件选择器并为每个选定的文件启动线程。

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,希望它很快会变得更好。

真诚的

ihavenoclue :)

【问题讨论】:

  • 真正的问题是为什么你想要一个包含 5000000 周多边形的文本文件?使用数据库可能是一个更好的主意。

标签: java multithreading shapefile geotools jts


【解决方案1】:
  1. 您不需要为每个文件创建一个新线程,因为创建新线程是一项昂贵的操作。相反,您可以让MultiThreadWriter 实现Runnable 并使用ThreadPoolExecuter 管理所有线程。

    多线程编写器

    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,当你重复写小片段时是more efficient

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

【讨论】:

    【解决方案2】:

    我更喜欢将文件内容作为对象列表读取,然后将列表拆分为子列表,然后为每个列表创建一个线程,例如:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      • 2019-02-27
      相关资源
      最近更新 更多