更快地迭代可观察列表 (JavaFX 8) 中的大量文件(对象)
Iterate faster over a large collection of files (objects) inside an Observable List (JavaFX 8)
我有一个 excel 文件,其中包含图像的所有文件名。这些图像的路径通过 <File>
class 存储在 Observable Collection
中,该路径来自包含所有图像的文件夹。我的目标是通过图像文件集合池中的匹配来创建这些文件名的超链接。
我想问一下我是否可以更快地遍历大量文件 classes 以便轻松获取它们的路径。
例如:
图片名称来自 Excel :
ABC_0001
集合的完整路径必须是:
C:\Users\admin\Desktop\Images\ABC_0001.jpg
为了得到他们的完整路径,我通过Stream进行迭代
我的程序:
- 使用 Apache POI 提取数据。
- 通过将每个数据转换为流式传输图像集合
他们的基本文件名与提取的数据。
- 通过以下方式获取结果并将完整路径存储在对象上
getAbsolutePath()
.
代码:
//storage during iteration
ObservableList<DetailedData> dataCollection = FXCollections.observableArrayList()
//Image collection containing over 13k Images listed via commons-io
ObservableList<File> IMAGE_COLLECTION = FXCollections.observableArrayList(FileUtils.listFiles(browsedFOLDER, new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
//Sheet data
Sheet sheet1 = wb.getsheetAt(0);
for (Row row: sheet1)
{
DetailedData data = new DetailedData();
//extracted data from excel
String FILENAME = row.getCell(0,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).getStringCellValue();
//to be filled up based on stream result.
String IMAGE_SOURCE = null;
//stream code with the help of commons-io
File IMAGE = IMAGE_COLLECTION.stream().filter(e -> FilenameUtils.getBaseName(e.getName()).toLowerCase().equals(FILENAME.toLowerCase())).findFirst().orElse(null);
if (IMAGE != null)
IMAGE_SOURCE = IMAGE.getAbsolutePath();
data.setFileName(FILENAME);
data.setFullPath(IMAGE_SOURCE);
dataCollection.add(data);
}
结果:
Excel rows = 9,400
Image Files = 13,000
Iteration Time = 120,000ms
结果应该显示正常还是可以变得更快?
我尝试使用 parallelStream()
,结果速度更快,但它消耗了更高的 CPU 使用率。
我在这个缓慢的迭代中测试了另一种方法。
似乎是因为在 foreach
中重复声明了 Stream
。
我尝试使用 Baeldung 的 solution <Supplier>
并将其与 parallelStream()
一起声明在循环外
示例代码:
Supplier<Stream<File>> streamSupplier = () -> imageCollection.parallelStream();
for (Row row : sheet)
{
File IMAGE = streamSupplier.get().filter(e -> FilenameUtils.getBaseName(e.getName()).toLowerCase().equals(FILENAME.toLowerCase())).findFirst().orElse(null);
if (IMAGE != null)
IMAGE_SOURCE = IMAGE.getAbsolutePath();
}
结果是 45000ms
如果我的做法不对,请指正。
如果你真的想加快你的搜索速度,你应该尽量不要重复做一些可以做一次的事情。例如,您可以使用两个循环。第一个准备搜索,第二个实际进行搜索。在您的过滤器中,您调用 FilenameUtils.getBaseName 并两次转换为小写。最好在第一个循环中只做一次这些事情并将结果字符串存储在列表中。在第二个循环中,您然后在此列表上进行搜索。
我也想知道你为什么在这里使用ObservableLists。一个简单的列表也可以。
此代码应该可以大大加快您的代码速度,但您的代码存在一些问题。
ObservableList<DetailedData> dataCollection = FXCollections.observableArrayList()
为什么要使用 ObservableList
?为什么这是 DetailedData
而不是 File
的列表。鉴于详细数据有setFileName
和setFullPath
。文件已有这些。
ObservableList<File> IMAGE_COLLECTION = FXCollections.observableArrayList(FileUtils.listFiles(browsedFOLDER, new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
为什么 ObservableList
?
这两个都是小东西,不过我很好奇
所以我认为你应该做的是使用 Map
。您的代码应该类似于下面的代码。
//storage during iteration
List<DetailedData> dataCollection = new ArrayList();
//Image collection containing over 13k Images listed via commons-io
List<File> IMAGE_COLLECTION = new ArrayList(FileUtils.listFiles(new File("C:\Users\blj0011\Pictures"), new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
//Use this to map file name to file
Map<String, File> map = new HashMap();
//Use this to add data to the map
IMAGE_COLLECTION.forEach((file) -> {map.put(file.getName().substring(0, file.getName().lastIndexOf(".")).toLowerCase(), file);});
for (Row row: sheet1)
{
//extracted data from excel
String FILENAME = row.getCell(0,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).getStringCellValue();
//If the map contains the file name, create `DetailedData` object. Then set data. Then add object to datacollection list.
if (map.containsKey(FILENAME.toLowerCase()))
{
DetailedData data = new DetailedData();
data.setFileName(FILENAME);
data.setFullPath(map.get(FILENAME.toLowerCase()).getAbsolutePath());
dataCollection.add(data);
}
}
代码中的注释
我仍然相信如果您使用 List<File> dataCollection = new ArrayList()
我有一个 excel 文件,其中包含图像的所有文件名。这些图像的路径通过 <File>
class 存储在 Observable Collection
中,该路径来自包含所有图像的文件夹。我的目标是通过图像文件集合池中的匹配来创建这些文件名的超链接。
我想问一下我是否可以更快地遍历大量文件 classes 以便轻松获取它们的路径。
例如:
图片名称来自 Excel :
ABC_0001
集合的完整路径必须是:
C:\Users\admin\Desktop\Images\ABC_0001.jpg
为了得到他们的完整路径,我通过Stream进行迭代
我的程序:
- 使用 Apache POI 提取数据。
- 通过将每个数据转换为流式传输图像集合 他们的基本文件名与提取的数据。
- 通过以下方式获取结果并将完整路径存储在对象上
getAbsolutePath()
.
代码:
//storage during iteration
ObservableList<DetailedData> dataCollection = FXCollections.observableArrayList()
//Image collection containing over 13k Images listed via commons-io
ObservableList<File> IMAGE_COLLECTION = FXCollections.observableArrayList(FileUtils.listFiles(browsedFOLDER, new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
//Sheet data
Sheet sheet1 = wb.getsheetAt(0);
for (Row row: sheet1)
{
DetailedData data = new DetailedData();
//extracted data from excel
String FILENAME = row.getCell(0,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).getStringCellValue();
//to be filled up based on stream result.
String IMAGE_SOURCE = null;
//stream code with the help of commons-io
File IMAGE = IMAGE_COLLECTION.stream().filter(e -> FilenameUtils.getBaseName(e.getName()).toLowerCase().equals(FILENAME.toLowerCase())).findFirst().orElse(null);
if (IMAGE != null)
IMAGE_SOURCE = IMAGE.getAbsolutePath();
data.setFileName(FILENAME);
data.setFullPath(IMAGE_SOURCE);
dataCollection.add(data);
}
结果:
Excel rows = 9,400
Image Files = 13,000
Iteration Time = 120,000ms
结果应该显示正常还是可以变得更快?
我尝试使用 parallelStream()
,结果速度更快,但它消耗了更高的 CPU 使用率。
我在这个缓慢的迭代中测试了另一种方法。
似乎是因为在 foreach
中重复声明了 Stream
。
我尝试使用 Baeldung 的 solution <Supplier>
并将其与 parallelStream()
示例代码:
Supplier<Stream<File>> streamSupplier = () -> imageCollection.parallelStream();
for (Row row : sheet)
{
File IMAGE = streamSupplier.get().filter(e -> FilenameUtils.getBaseName(e.getName()).toLowerCase().equals(FILENAME.toLowerCase())).findFirst().orElse(null);
if (IMAGE != null)
IMAGE_SOURCE = IMAGE.getAbsolutePath();
}
结果是 45000ms
如果我的做法不对,请指正。
如果你真的想加快你的搜索速度,你应该尽量不要重复做一些可以做一次的事情。例如,您可以使用两个循环。第一个准备搜索,第二个实际进行搜索。在您的过滤器中,您调用 FilenameUtils.getBaseName 并两次转换为小写。最好在第一个循环中只做一次这些事情并将结果字符串存储在列表中。在第二个循环中,您然后在此列表上进行搜索。
我也想知道你为什么在这里使用ObservableLists。一个简单的列表也可以。
此代码应该可以大大加快您的代码速度,但您的代码存在一些问题。
ObservableList<DetailedData> dataCollection = FXCollections.observableArrayList()
为什么要使用ObservableList
?为什么这是DetailedData
而不是File
的列表。鉴于详细数据有setFileName
和setFullPath
。文件已有这些。ObservableList<File> IMAGE_COLLECTION = FXCollections.observableArrayList(FileUtils.listFiles(browsedFOLDER, new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
为什么ObservableList
?
这两个都是小东西,不过我很好奇
所以我认为你应该做的是使用 Map
。您的代码应该类似于下面的代码。
//storage during iteration
List<DetailedData> dataCollection = new ArrayList();
//Image collection containing over 13k Images listed via commons-io
List<File> IMAGE_COLLECTION = new ArrayList(FileUtils.listFiles(new File("C:\Users\blj0011\Pictures"), new String[]{"JPG", "JPEG", "TIF", "TIFF", "jpg", "jpeg", "tif", "tiff"}, true));
//Use this to map file name to file
Map<String, File> map = new HashMap();
//Use this to add data to the map
IMAGE_COLLECTION.forEach((file) -> {map.put(file.getName().substring(0, file.getName().lastIndexOf(".")).toLowerCase(), file);});
for (Row row: sheet1)
{
//extracted data from excel
String FILENAME = row.getCell(0,Row.MissingCellPolicy.CREATE_NULL_AS_BLANK).getStringCellValue();
//If the map contains the file name, create `DetailedData` object. Then set data. Then add object to datacollection list.
if (map.containsKey(FILENAME.toLowerCase()))
{
DetailedData data = new DetailedData();
data.setFileName(FILENAME);
data.setFullPath(map.get(FILENAME.toLowerCase()).getAbsolutePath());
dataCollection.add(data);
}
}
代码中的注释
我仍然相信如果您使用 List<File> dataCollection = new ArrayList()