Java實現(xiàn)Excel圖片URL篩選與大小檢測的全過程
引言
在數(shù)據(jù)處理場景中,我們常需篩選Excel中的圖片URL。本文分享一個完整的Java方案,涵蓋從讀取圖片URL到檢測有效性、篩選大小,再到生成新Excel文件的全過程,同時講解開發(fā)與優(yōu)化過程,幫助你解決實際業(yè)務(wù)中的數(shù)據(jù)篩選和清洗需求。
一、問題背景
客戶現(xiàn)場圖片數(shù)據(jù),要求如下:
- 讀取Excel的圖片URL。
- 檢測URL有效性并獲取圖片大小。
- 篩選大于1MB或無法訪問(404)的圖片記錄。
- 保留原始數(shù)據(jù)格式,尤其是日期類型數(shù)據(jù)。
- 生成篩選后的新Excel文件。
二、核心實現(xiàn)方案
(一)技術(shù)選型
為實現(xiàn)上述目標(biāo),我們主要采用以下技術(shù):
- Apache POI :用于讀取和寫入Excel文件,支持對單元格數(shù)據(jù)的操作及格式處理,能方便地處理XLSX文件。
- HttpURLConnection :用于檢測圖片URL的有效性并獲取圖片大小,通過發(fā)送HEAD請求獲取資源信息,避免下載整個圖片浪費帶寬。
(二)關(guān)鍵代碼實現(xiàn)
1. Excel文件讀取與寫入
package cn.api.server;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ImageSizeFilter {
private static final Logger LOGGER = Logger.getLogger(ImageSizeFilter.class.getName());
private static final int CONNECT_TIMEOUT = 5000;
private static final int READ_TIMEOUT = 5000;
private static final double BYTES_TO_MEGABYTES = 1024.0 * 1024.0;
private static final double SIZE_THRESHOLD = 1.0;
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
public static void main(String[] args) {
String inputFilePath = "C:/Users/admin/Desktop/圖片數(shù)據(jù).xlsx";
String outputFilePath = "C:/Users/admin/Desktop/圖片數(shù)據(jù)_篩選后.xlsx";
System.out.println("開始處理Excel文件...");
System.out.println("輸入文件: " + inputFilePath);
long startTime = System.currentTimeMillis();
int processedCount = 0;
int filteredCount = 0;
try (FileInputStream inputStream = new FileInputStream(new File(inputFilePath));
Workbook workbook = new XSSFWorkbook(inputStream)) {
Sheet sheet = workbook.getSheetAt(0);
int totalRows = sheet.getLastRowNum();
System.out.println("發(fā)現(xiàn) " + totalRows + " 條數(shù)據(jù)記錄");
try (Workbook newWorkbook = new XSSFWorkbook()) {
Sheet newSheet = newWorkbook.createSheet();
Row headerRow = sheet.getRow(0);
Row newHeaderRow = newSheet.createRow(0);
// 復(fù)制表頭并添加新列
copyRow(headerRow, newHeaderRow);
createHeaderCell(newHeaderRow, "圖片大?。∕)");
createHeaderCell(newHeaderRow, "狀態(tài)");
int newRowIndex = 1;
for (int i = 1; i <= totalRows; i++) {
if (i % 100 == 0) {
System.out.println("已處理 " + i + "/" + totalRows + " 行");
}
Row row = sheet.getRow(i);
if (row != null) {
Cell urlCell = row.getCell(7);
if (urlCell != null) {
String imageUrl = getCellValue(urlCell);
if (isValidUrl(imageUrl)) {
processedCount++;
long sizeInBytes = getImageSize(imageUrl);
double sizeInMegabytes = sizeInBytes / BYTES_TO_MEGABYTES;
boolean is404 = sizeInBytes == 0 && isUrl404(imageUrl);
if (sizeInMegabytes > SIZE_THRESHOLD || is404) {
filteredCount++;
Row newRow = newSheet.createRow(newRowIndex++);
copyRowWithDateHandling(row, newRow, workbook, newWorkbook);
newRow.createCell(headerRow.getLastCellNum()).setCellValue(sizeInMegabytes);
newRow.createCell(headerRow.getLastCellNum() + 1).setCellValue(is404 ? "404" : "圖片過大");
}
}
}
}
}
try (FileOutputStream outputStream = new FileOutputStream(new File(outputFilePath))) {
newWorkbook.write(outputStream);
}
long endTime = System.currentTimeMillis();
System.out.println("篩選完成!耗時:" + (endTime - startTime) / 1000 + " 秒");
System.out.println("處理記錄數(shù):" + processedCount);
System.out.println("篩選出的記錄數(shù):" + filteredCount);
System.out.println("結(jié)果保存至:" + outputFilePath);
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "處理文件時出錯", e);
}
}
}
在上述代碼中,我們通過FileInputStream讀取原始Excel文件,利用XSSFWorkbook將其加載為Workbook對象。然后獲取第一個工作表(Sheet),并遍歷其行數(shù)據(jù)。對于篩選出的符合條件的行,我們創(chuàng)建新的Workbook對象(newWorkbook),并在其中創(chuàng)建新的工作表(newSheet),將原始表頭復(fù)制過來并添加新列 “圖片大?。∕)” 和 “狀態(tài)”,用于存儲圖片大小信息和篩選狀態(tài)。
2. URL檢測與圖片大小獲取
// 獲取圖片大?。ㄗ止?jié))
private static long getImageSize(String imageUrl) {
HttpURLConnection connection = null;
try {
URL url = new URL(imageUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD");
connection.setConnectTimeout(CONNECT_TIMEOUT);
connection.setReadTimeout(READ_TIMEOUT);
connection.connect();
return connection.getResponseCode() == HttpURLConnection.HTTP_OK
? connection.getContentLength() : 0;
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "獲取圖片大小異常", e);
return 0;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
// 判斷URL是否404
private static boolean isUrl404(String imageUrl) {
HttpURLConnection connection = null;
try {
URL url = new URL(imageUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD");
connection.setConnectTimeout(CONNECT_TIMEOUT);
connection.setReadTimeout(READ_TIMEOUT);
connection.connect();
return connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND;
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "檢測404異常", e);
return false;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
這里,我們使用HttpURLConnection發(fā)送HEAD請求到指定的圖片URL。HEAD請求不會下載資源實體內(nèi)容,只請求資源的頭部信息,這樣可以快速獲取圖片的相關(guān)信息,如大小等。通過調(diào)用connection.getContentLength()方法可獲取圖片大?。ㄒ宰止?jié)為單位)。同時,我們還定義了isUrl404()方法來判斷URL是否返回404狀態(tài)碼,以便識別無法訪問的圖片。
3. 單元格數(shù)據(jù)讀取與處理
// 獲取單元格值(處理日期格式)
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
int cellType = cell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
return cell.getStringCellValue();
case Cell.CELL_TYPE_NUMERIC:
return DateUtil.isCellDateFormatted(cell)
? DATE_FORMAT.format(cell.getDateCellValue())
: String.valueOf(cell.getNumericCellValue());
case Cell.CELL_TYPE_BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case Cell.CELL_TYPE_FORMULA:
return cell.getCellFormula();
default:
return "";
}
}
在讀取Excel單元格數(shù)據(jù)時,需考慮不同類型的數(shù)據(jù)處理方式。對于字符串類型單元格,直接獲取其字符串值;對于數(shù)值型單元格,若其為日期格式(通過DateUtil.isCellDateFormatted(cell)判斷),則將其轉(zhuǎn)換為Date對象并按照指定格式(yyyy - MM - dd)格式化為字符串,否則以常規(guī)數(shù)值形式返回;對于布爾型單元格,返回對應(yīng)的布爾值字符串;對于公式型單元格,返回其公式內(nèi)容。
4. 行數(shù)據(jù)復(fù)制
// 復(fù)制行(表頭專用,不處理日期)
private static void copyRow(Row sourceRow, Row targetRow) {
for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
Cell sourceCell = sourceRow.getCell(i);
Cell targetCell = targetRow.createCell(i);
if (sourceCell != null) {
int cellType = sourceCell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
targetCell.setCellValue(sourceCell.getNumericCellValue());
break;
case Cell.CELL_TYPE_BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
targetCell.setCellFormula(sourceCell.getCellFormula());
break;
}
}
}
}
// 復(fù)制行(數(shù)據(jù)行專用,處理日期格式)
private static void copyRowWithDateHandling(Row sourceRow, Row targetRow,
Workbook sourceWorkbook, Workbook targetWorkbook) {
for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
Cell sourceCell = sourceRow.getCell(i);
Cell targetCell = targetRow.createCell(i);
if (sourceCell != null) {
int cellType = sourceCell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(sourceCell)) {
targetCell.setCellValue(sourceCell.getDateCellValue());
CellStyle newCellStyle = targetWorkbook.createCellStyle();
newCellStyle.cloneStyleFrom(sourceCell.getCellStyle());
targetCell.setCellStyle(newCellStyle);
} else {
targetCell.setCellValue(sourceCell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
targetCell.setCellFormula(sourceCell.getCellFormula());
break;
}
}
}
}
為實現(xiàn)行數(shù)據(jù)的復(fù)制,我們定義了兩個方法。copyRow()方法用于復(fù)制表頭行數(shù)據(jù),直接根據(jù)單元格類型設(shè)置目標(biāo)單元格的值;copyRowWithDateHandling()方法用于復(fù)制數(shù)據(jù)行,在處理數(shù)值型單元格時,會判斷其是否為日期格式,若是,則將其作為日期處理并復(fù)制對應(yīng)的單元格樣式,以確保日期格式在新Excel文件中正確顯示。
三、優(yōu)化過程詳解
(一)初始實現(xiàn)問題
在最初的實現(xiàn)中,我們遇到了以下問題:
- 日期格式處理不當(dāng) :數(shù)值型日期被轉(zhuǎn)為普通數(shù)字,導(dǎo)致數(shù)據(jù)展示不符合預(yù)期,例如原本在Excel中顯示為 “2024 - 05 - 20” 的日期,在讀取后變?yōu)橐淮當(dāng)?shù)字。
- Java 8兼容性問題 :最初代碼使用了Java 12+的switch表達式,但在實際部署環(huán)境中需兼容Java 8,導(dǎo)致代碼無法正常運行。
- 缺少完整的行復(fù)制方法 :在復(fù)制行數(shù)據(jù)時,未能全面處理各種單元格類型及樣式,導(dǎo)致新生成的Excel文件數(shù)據(jù)格式混亂。
(二)日期格式處理優(yōu)化
通過引入DateUtil.isCellDateFormatted()方法檢測單元格是否為日期格式,并使用SimpleDateFormat將Date對象格式化為指定字符串形式,成功解決了日期格式處理問題。優(yōu)化后的代碼如下:
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
int cellType = cell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
return cell.getStringCellValue();
case Cell.CELL_TYPE_NUMERIC:
return DateUtil.isCellDateFormatted(cell)
? DATE_FORMAT.format(cell.getDateCellValue())
: String.valueOf(cell.getNumericCellValue());
case Cell.CELL_TYPE_BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case Cell.CELL_TYPE_FORMULA:
return cell.getCellFormula();
default:
return "";
}
}
(三)Java 8兼容性改造
將枚舉和switch表達式改為傳統(tǒng)寫法,使用Cell.CELL_TYPE_* 常量,并重構(gòu)行復(fù)制方法,使其在Java 8環(huán)境下穩(wěn)定運行。改造后的行復(fù)制方法如下:
private static void copyRowWithDateHandling(Row sourceRow, Row targetRow,
Workbook sourceWorkbook, Workbook targetWorkbook) {
for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
Cell sourceCell = sourceRow.getCell(i);
Cell targetCell = targetRow.createCell(i);
if (sourceCell != null) {
int cellType = sourceCell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(sourceCell)) {
targetCell.setCellValue(sourceCell.getDateCellValue());
CellStyle newCellStyle = targetWorkbook.createCellStyle();
newCellStyle.cloneStyleFrom(sourceCell.getCellStyle());
targetCell.setCellStyle(newCellStyle);
} else {
targetCell.setCellValue(sourceCell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
targetCell.setCellFormula(sourceCell.getCellFormula());
break;
}
}
}
}
(四)完整功能實現(xiàn)
經(jīng)過上述優(yōu)化后,我們的代碼實現(xiàn)了以下功能:
- 準(zhǔn)確讀取Excel文件中的數(shù)據(jù),包括各種類型單元格數(shù)據(jù),特別是正確處理了日期格式數(shù)據(jù),避免了數(shù)據(jù)變形問題。
- 通過HttpURLConnection有效檢測圖片URL的合法性及獲取圖片大小,能夠精準(zhǔn)篩選出大于1MB或無法訪問(404)的圖片記錄。
- 在生成新Excel文件時,完整保留了原始數(shù)據(jù)的格式,并新增列存儲圖片大小信息和篩選狀態(tài),方便用戶查看篩選結(jié)果。
- 兼容Java 8環(huán)境,確保代碼在不同版本的JDK下穩(wěn)定運行,適應(yīng)更多實際應(yīng)用場景。
四、使用說明
(一)環(huán)境準(zhǔn)備
- JDK版本 :需安裝JDK 8或以上版本。
- Maven依賴 :在項目中引入以下Apache POI相關(guān)依賴,用于操作Excel文件。
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
(二)運行方式
- 根據(jù)實際需求修改main方法中的輸入文件路徑(inputFilePath)和輸出文件路徑(outputFilePath),指定待處理的Excel文件和生成結(jié)果的保存位置。
- 編譯項目,運行ImageSizeFilter類的main方法,程序?qū)⒆詣娱_始處理Excel文件,并在控制臺輸出處理進度和結(jié)果信息。
(三)自定義配置
- 圖片大小閾值 :可通過修改SIZE_THRESHOLD常量的值來調(diào)整圖片大小篩選閾值,例如將其改為2.0,則篩選出大于2MB的圖片。
- 網(wǎng)絡(luò)連接超時時間 :根據(jù)網(wǎng)絡(luò)狀況調(diào)整CONNECT_TIMEOUT和READ_TIMEOUT常量的值,以優(yōu)化圖片URL檢測過程中的網(wǎng)絡(luò)連接性能。
- 日期顯示格式 :若需更改日期在新Excel文件中的顯示格式,可修改DATE_FORMAT常量對應(yīng)的SimpleDateFormat模式,如改為 “yyyy/MM/dd HH:mm:ss” 以包含時間信息。
五、技術(shù)總結(jié)與擴展方向
(一)關(guān)鍵技術(shù)點總結(jié)
- POI操作Excel :熟練掌握POI對Excel文件的讀寫操作,包括工作簿、工作表、行、單元格的創(chuàng)建、獲取及數(shù)據(jù)讀寫,是實現(xiàn)本功能的核心基礎(chǔ)。通過合理使用CellStyle等類,可有效控制單元格數(shù)據(jù)的顯示格式。
- HttpURLConnection網(wǎng)絡(luò)請求 :利用HttpURLConnection發(fā)送HEAD請求檢測圖片URL的有效性及獲取圖片大小,是一種高效且節(jié)省帶寬的方法。正確設(shè)置請求方法、超時時間等參數(shù),可確保網(wǎng)絡(luò)請求的穩(wěn)定性和準(zhǔn)確性。
- Java 8兼容性編程 :在實際項目開發(fā)中,考慮到不同環(huán)境的兼容性需求,避免使用過高版本的Java特性,采用傳統(tǒng)語法結(jié)構(gòu)和常量,能提高代碼的通用性和可移植性。
- 數(shù)據(jù)格式處理 :對于Excel中的日期等特殊數(shù)據(jù)類型,需深入了解其存儲和展示原理,通過合理的判斷和轉(zhuǎn)換邏輯,確保數(shù)據(jù)在程序處理過程中及最終結(jié)果中的準(zhǔn)確性。
(二)可能的擴展方向
- 多線程處理 :針對大規(guī)模數(shù)據(jù)處理場景,可考慮引入多線程技術(shù),將Excel文件的行數(shù)據(jù)分配到多個線程同時進行圖片URL檢測和篩選操作,從而顯著提高處理效率,減少程序運行時間。
- 圖片預(yù)覽功能 :在篩選出不符合要求的圖片后,為進一步方便用戶查看和分析,可增加圖片預(yù)覽功能。例如,利用圖像處理庫將圖片縮略圖嵌入到生成的新Excel文件中,或開發(fā)一個簡單的界面程序展示圖片預(yù)覽。
- 支持多種文件格式 :除了Excel文件(.xlsx),還可擴展程序支持CSV等其他常見數(shù)據(jù)文件格式,以適應(yīng)更廣泛的數(shù)據(jù)處理需求。這需要根據(jù)不同文件格式的特點,調(diào)整數(shù)據(jù)讀取、寫入及格式處理等相關(guān)代碼邏輯。
- 數(shù)據(jù)庫存儲與查詢 :對于經(jīng)過篩選的圖片數(shù)據(jù)及相關(guān)信息,可考慮將其存儲到數(shù)據(jù)庫中,實現(xiàn)數(shù)據(jù)的持久化。同時,借助數(shù)據(jù)庫的查詢功能,能夠方便地對篩選結(jié)果進行后續(xù)的統(tǒng)計分析、數(shù)據(jù)檢索等操作,為用戶提供了一種更靈活的數(shù)據(jù)管理方式。
六、結(jié)語
通過本案例,我們深刻體會到Java在數(shù)據(jù)處理領(lǐng)域的強大能力以及在實際業(yè)務(wù)開發(fā)中的廣泛應(yīng)用。借助Apache POI和HttpURLConnection等工具和技術(shù),能夠高效地實現(xiàn)Excel圖片URL的篩選與大小檢測功能,并解決實際業(yè)務(wù)中的數(shù)據(jù)清洗問題。在開發(fā)過程中,注重細節(jié)處理,如數(shù)據(jù)格式保留、跨版本兼容性等,是提升程序質(zhì)量和用戶體驗的關(guān)鍵。未來,隨著業(yè)務(wù)需求的不斷拓展和技術(shù)的持續(xù)發(fā)展,我們可以對現(xiàn)有程序進行進一步優(yōu)化和擴展,以滿足更多樣化的數(shù)據(jù)處理場景。
希望本文對你有所幫助,如果你在實現(xiàn)過程中遇到任何問題或有任何改進建議,歡迎在評論區(qū)留言交流。
附錄,所有代碼:
package cn.api.server;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ImageSizeFilter {
private static final Logger LOGGER = Logger.getLogger(ImageSizeFilter.class.getName());
// 設(shè)置連接超時時間(毫秒)
private static final int CONNECT_TIMEOUT = 5000;
// 設(shè)置讀取超時時間(毫秒)
private static final int READ_TIMEOUT = 5000;
// 定義字節(jié)到兆字節(jié)的轉(zhuǎn)換系數(shù)
private static final double BYTES_TO_MEGABYTES = 1024.0 * 1024.0;
// 圖片大小閾值(MB)
private static final double SIZE_THRESHOLD = 1.0;
// 日期格式
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
public static void main(String[] args) {
String inputFilePath = "C:/Users/admin/Desktop/圖片數(shù)據(jù).xlsx";
String outputFilePath = "C:/Users/admin/Desktop/圖片數(shù)據(jù)_篩選后.xlsx";
System.out.println("開始處理Excel文件...");
System.out.println("輸入文件: " + inputFilePath);
long startTime = System.currentTimeMillis();
int processedCount = 0;
int filteredCount = 0;
try (FileInputStream inputStream = new FileInputStream(new File(inputFilePath));
Workbook workbook = new XSSFWorkbook(inputStream)) {
Sheet sheet = workbook.getSheetAt(0);
int totalRows = sheet.getLastRowNum();
System.out.println("發(fā)現(xiàn) " + totalRows + " 條數(shù)據(jù)記錄");
try (Workbook newWorkbook = new XSSFWorkbook()) {
Sheet newSheet = newWorkbook.createSheet();
// 復(fù)制表頭,并新增圖片大小列和狀態(tài)列
Row headerRow = sheet.getRow(0);
Row newHeaderRow = newSheet.createRow(0);
copyRow(headerRow, newHeaderRow);
createHeaderCell(newHeaderRow, "圖片大?。∕)");
createHeaderCell(newHeaderRow, "狀態(tài)");
int newRowIndex = 1;
for (int i = 1; i <= totalRows; i++) {
if (i % 100 == 0) {
System.out.println("已處理 " + i + "/" + totalRows + " 行");
}
Row row = sheet.getRow(i);
if (row != null) {
// 根據(jù)實踐的Excel表設(shè)置數(shù)字,這里是第8列
Cell urlCell = row.getCell(7);
if (urlCell != null) {
String imageUrl = getCellValue(urlCell);
if (isValidUrl(imageUrl)) {
processedCount++;
long sizeInBytes = getImageSize(imageUrl);
double sizeInMegabytes = sizeInBytes / BYTES_TO_MEGABYTES;
boolean is404 = false;
if (sizeInBytes == 0) {
is404 = isUrl404(imageUrl);
}
if (sizeInMegabytes > SIZE_THRESHOLD || is404) {
filteredCount++;
Row newRow = newSheet.createRow(newRowIndex++);
copyRowWithDateHandling(row, newRow, workbook, newWorkbook);
// 在新行的倒數(shù)第二列寫入圖片大小(M)
newRow.createCell(headerRow.getLastCellNum()).setCellValue(sizeInMegabytes);
// 在新行的最后一列寫入狀態(tài)
newRow.createCell(headerRow.getLastCellNum() + 1).setCellValue(is404 ? "404" : "圖片過大");
}
} else {
LOGGER.log(Level.WARNING, "發(fā)現(xiàn)不合法的URL (行 {0}): {1}", new Object[]{i, imageUrl});
}
}
}
}
try (FileOutputStream outputStream = new FileOutputStream(new File(outputFilePath))) {
newWorkbook.write(outputStream);
}
long endTime = System.currentTimeMillis();
System.out.println("篩選完成!");
System.out.println("處理時間: " + (endTime - startTime) / 1000 + " 秒");
System.out.println("處理記錄數(shù): " + processedCount);
System.out.println("篩選出的記錄數(shù): " + filteredCount);
System.out.println("結(jié)果保存到: " + outputFilePath);
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "寫入輸出文件時出錯", e);
System.err.println("錯誤: 無法寫入輸出文件: " + outputFilePath);
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "讀取輸入文件時出錯", e);
System.err.println("錯誤: 無法讀取輸入文件: " + inputFilePath);
}
}
private static long getImageSize(String imageUrl) {
HttpURLConnection connection = null;
try {
URL url = new URL(imageUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD");
connection.setConnectTimeout(CONNECT_TIMEOUT);
connection.setReadTimeout(READ_TIMEOUT);
connection.connect();
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
return connection.getContentLength();
} else {
LOGGER.log(Level.WARNING, "獲取圖片大小失敗,URL: {0},響應(yīng)碼: {1}", new Object[]{imageUrl, responseCode});
return 0;
}
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "獲取圖片大小IO異常,URL: " + imageUrl, e);
return 0;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
private static boolean isUrl404(String imageUrl) {
HttpURLConnection connection = null;
try {
URL url = new URL(imageUrl);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("HEAD");
connection.setConnectTimeout(CONNECT_TIMEOUT);
connection.setReadTimeout(READ_TIMEOUT);
connection.connect();
return connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND;
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "判斷 URL 是否 404 時發(fā)生 IO 異常,URL: " + imageUrl, e);
return false;
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
// 兼容Java 8的寫法
int cellType = cell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
return cell.getStringCellValue();
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
Date date = cell.getDateCellValue();
return DATE_FORMAT.format(date);
} else {
return String.valueOf(cell.getNumericCellValue());
}
case Cell.CELL_TYPE_BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case Cell.CELL_TYPE_FORMULA:
return cell.getCellFormula();
default:
return "";
}
}
private static boolean isValidUrl(String url) {
if (url == null || url.trim().isEmpty()) {
return false;
}
try {
new URL(url);
return true;
} catch (MalformedURLException e) {
return false;
}
}
/**
* 復(fù)制行(用于表頭復(fù)制,不處理日期格式)
*/
private static void copyRow(Row sourceRow, Row targetRow) {
for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
Cell sourceCell = sourceRow.getCell(i);
Cell targetCell = targetRow.createCell(i);
if (sourceCell != null) {
int cellType = sourceCell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
targetCell.setCellValue(sourceCell.getNumericCellValue());
break;
case Cell.CELL_TYPE_BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
targetCell.setCellFormula(sourceCell.getCellFormula());
break;
default:
break;
}
}
}
}
/**
* 復(fù)制行并處理日期格式(用于數(shù)據(jù)行復(fù)制)
*/
private static void copyRowWithDateHandling(Row sourceRow, Row targetRow, Workbook sourceWorkbook, Workbook targetWorkbook) {
for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
Cell sourceCell = sourceRow.getCell(i);
Cell targetCell = targetRow.createCell(i);
if (sourceCell != null) {
int cellType = sourceCell.getCellType();
switch (cellType) {
case Cell.CELL_TYPE_STRING:
targetCell.setCellValue(sourceCell.getStringCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(sourceCell)) {
targetCell.setCellValue(sourceCell.getDateCellValue());
CellStyle newCellStyle = targetWorkbook.createCellStyle();
newCellStyle.cloneStyleFrom(sourceCell.getCellStyle());
targetCell.setCellStyle(newCellStyle);
} else {
targetCell.setCellValue(sourceCell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_BOOLEAN:
targetCell.setCellValue(sourceCell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
targetCell.setCellFormula(sourceCell.getCellFormula());
break;
default:
break;
}
}
}
}
private static void createHeaderCell(Row headerRow, String headerValue) {
Cell headerCell = headerRow.createCell(headerRow.getLastCellNum());
headerCell.setCellValue(headerValue);
CellStyle style = headerCell.getSheet().getWorkbook().createCellStyle();
Font font = headerCell.getSheet().getWorkbook().createFont();
font.setBold(true);
style.setFont(font);
headerCell.setCellStyle(style);
}
}
以上就是Java實現(xiàn)Excel圖片URL篩選與大小檢測的全過程的詳細內(nèi)容,更多關(guān)于Java Excel圖片URL篩選與檢測的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
關(guān)于Spring事務(wù)隔離、傳播屬性與@Transactional注解
這篇文章主要介紹了關(guān)于事務(wù)隔離、Spring傳播屬性與@Transactional注解,如果一組處理步驟或者全部發(fā)生或者一步也不執(zhí)行,我們稱該組處理步驟為一個事務(wù),需要的朋友可以參考下2023-05-05
項目打包成jar后包無法讀取src/main/resources下文件的解決
本文主要介紹了項目打包成jar后包無法讀取src/main/resources下文件的解決,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04

