眾所周知,遞歸編程是一項有爭議的技術(shù),因為它需要大量的內(nèi)存,但是它能簡化一些編程任務(wù)。基本上,一個遞歸操作都是程序調(diào)用自己傳遞參數(shù)修改的值或者參數(shù)傳遞到當前的程序循環(huán)中。遞歸編程通常用來計算階乘斐波那契數(shù)列,回文,謝爾賓斯基地毯等問題。下面的代碼演示了用遞歸實現(xiàn)的階乘。
/** * Calculate the factorial of n (n! = 1 * 2 * 3 * … * n). * * @param n the number to calculate the factorial of. * @return n! - the factorial of n. */ static int fact(int n) { // Base Case: // If n <= 1 then n! = 1. if (n <= 1) { return 1; } // Recursive Case: // If n > 1 then n! = n * (n-1)! else { return n * fact(n-1); } }
許多文件的操作需要訪問文件樹結(jié)構(gòu)下的文件,只用遞歸操作再合適不過。NIO.2 在接口中封裝了遍歷文件樹的過程。這個接口叫FileVisitor,在
java.nio.file
包中。
這一節(jié)我們從FileVisitor學(xué)起,一旦你熟悉了
FileVisitor,你就能開發(fā)一系列執(zhí)行操作包括文件樹的游歷,文件的查找,刪除,拷貝和移動。
-----------------------------------------------------------------------------------------------------------------------
FileVisitor接口
如前面提到的,FileVisitor接口提供了對文件樹遞歸遍歷的支持。接口中的方法可以在訪問文件的時候,目錄訪問之前,目錄訪問之后,發(fā)生失敗后采取控制,一旦你獲得控制,你就能決定如何訪問文件,通過
FileVisitResult枚舉決定當
訪問下一個訪問結(jié)果時如何處理。這個枚舉有四個枚舉常量:
FileVisitResult.CONTINUE
: 這個訪問結(jié)果表明,遍歷過程應(yīng)該繼續(xù)。根據(jù)FileVisitor
的方法返回類型可以翻譯成不同的行為。FileVisitResult.SKIP_SIBLINGS
: 這個訪問結(jié)果表明,遍歷過程應(yīng)該繼續(xù)沒有訪問這個文件或目錄的兄弟姐妹節(jié)點。FileVisitResult.SKIP_SUBTREE
: 這次訪問結(jié)果表明,遍歷過程應(yīng)該繼續(xù)除了這個目錄中剩下其他的條目。FileVisitResult.TERMINATE
: 這次訪問結(jié)果表明,遍歷過程應(yīng)該終止。這些枚舉的常亮可以用下面的代碼進行遍歷。
for (FileVisitResult constant : FileVisitResult.values()) System.out.PRintln(constant);
下面的章節(jié)來討論實現(xiàn)FileVisitor
接口的方法如何控制遍歷過程。
FileVisitor.visitFile()方法
這個方法用在一個在目錄中的文件時被調(diào)用。通常,這個方法返回CONTINUE 或
TERMINATE。 例如:當尋找一個文件時,方法應(yīng)該返回
CONTINUE知道文件找到,和文件找到后返回
TERMINATE。
當方法調(diào)用后,它接收一個file的引用一節(jié)文件的一些基本屬性。如果發(fā)生IO異常,它會拋出IOException異常。次方法的簽名如下:
FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException
FileVisitor.preVisitDirectory()方法
此方法在開始訪問以為目錄的條目開始之前被調(diào)用。如果方法返回CONTINUE
則 目錄中的條目將被訪問。如果方法返回SKIP_SUBTREE
則目錄里的條目不被訪問。當然你也可以訪問文件或是目錄的兄弟節(jié)點如果方法返回SKIP_SIBLINGS
。方法簽名為:
FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws IOException
FileVisitor.postVisitDirectory()方法
當整個目錄里的所有條目訪問以后或訪問突然結(jié)束時此方法被調(diào)用。當這個方法被調(diào)用后,它會持有目錄和IOException的引用——如果沒有異常發(fā)生則會返回null,或發(fā)生一個異常返回對應(yīng)的錯誤。下面是此方法的簽名:
FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException
FileVisitor.visitFileFailed()方法
因為各種不同的原因?qū)е挛募荒茉L問時此方法被調(diào)用,例如文件的屬性不允許讀取或目錄不允許打開。方法簽名如下:
FileVisitResult visitFileFailed(T file, IOException exc) throws IOException
----------------------------------------------------------------------------------------------------------------
SimpleFileVisitor類
實現(xiàn)FileVisitor接口必須要求實現(xiàn)所有的方法,如果你只需要實現(xiàn)其中一個或幾個方法,就顯得有些不合需要的。在這種情況下,繼承
SimpleFileVisitor類就顯得簡單很多,它實現(xiàn)了
FileVisitor
接口。
例如,你想遍歷所有的目錄并列出所有的名字,你可以很容易地使用postVisitDirectory()
和visitFileFailed() 方法。
class ListTree extends SimpleFileVisitor<Path> { @Override public FileVisitResult postVisitDirectory(Path dir, IOException exc) { System.out.println("Visited directory: " + dir.toString()); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Path file, IOException exc) { System.out.println(exc); return FileVisitResult.CONTINUE; } }
開始遞歸過程
一旦你創(chuàng)建了遞歸機制,就可以開始這個過程通過調(diào)用Files.walkFileTree()
方法。最簡單的Files.walkFileTree()
的方法傳遞一個開始文件(通常是根),還有一個 文件訪問者對象去調(diào)用每個文件。例如,下面的例子。
Path listDir = Paths.get("C:/rafaelnadal"); //define the starting file tree ListTree walk = new ListTree(); //instantiate the walk try{ Files.walkFileTree(listDir, walk); //start the walk } catch(IOException e){ System.err.println(e); }
第二個重載的walkFileTree()方法第一個參數(shù)是開始的文件,然后是自定義的遍歷的選項,目錄層級的最大訪問數(shù),還有 walk 實例。
Path listDir = Paths.get("C:/rafaelnadal"); //define the starting file ListTree walk = new ListTree(); //instantiate the walk EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); //follow links try{ Files.walkFileTree(listDir, opts, Integer.MAX_VALUE, walk); //start the walk } catch(IOException e){ System.err.println(e); }
-----------------------------------------------------------------------------------------------------------------------------------
寫一個文件搜索程序
大多數(shù)操作系統(tǒng)會提供專用的工具用來搜索文件(例如,在linux下可以使用find命令,同時windows也提供了文件搜索工具),從最簡單的搜索,到高級搜索,所有的工具都是用同一種方式工作:你指定搜索條件然后等待工具返回匹配的文件。但是,如果你要使用編程方式完成這個功能,F(xiàn)ileVisitor接口能幫助你實現(xiàn)遍歷查找。無論你是通過名字,擴展名來查找文件還是通過正則表達式在文件內(nèi)部搜索文本或符號,這些方法都是訪問每個文件和執(zhí)行一些檢查來確定這個文件是否滿足你的搜索條件。
如果你基于FileVisitor來實現(xiàn)你的文件搜索工具,你需要注意下面幾點:
postVisitDirectory()
方法來實現(xiàn)比較。visitFileFailed()
方法會返回 FileVisitResult.CONTINUE
,因為這個問題不會決定整個搜索過程終止。通過名字檢索文件
下面的程序通過名字對文件進行檢索rafa_1.jpg在默認目錄下,當找到后終止檢索。
import java.io.IOException;import java.nio.file.FileSystems;import java.nio.file.FileVisitOption;import java.nio.file.FileVisitResult;import java.nio.file.FileVisitor;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.Paths;import java.nio.file.attribute.BasicFileAttributes;import java.util.EnumSet;class Search implements FileVisitor { private final Path searchedFile; public boolean found; public Search(Path searchedFile) { this.searchedFile = searchedFile; this.found = false; }void search(Path file) throws IOException { Path name = file.getFileName(); if (name != null && name.equals(searchedFile)) { System.out.println("Searched file was found: " + searchedFile + " in " + file.toRealPath().toString()); found = true; } } @Override public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException { System.out.println("Visited: " + (Path) dir); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException { search((Path) file); if (!found) { return FileVisitResult.CONTINUE; } else { return FileVisitResult.TERMINATE; } } @Override public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException { //report an error if necessary return FileVisitResult.CONTINUE; }}class Main { public static void main(String[] args) throws IOException { Path searchFile = Paths.get("rafa_1.jpg"); Search walk = new Search(searchFile); EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories(); for (Path root : dirs) { if (!walk.found) { Files.walkFileTree(root, opts, Integer.MAX_VALUE, walk); } } if (!walk.found) { System.out.println("The file " + searchFile + " was not found!"); } }}
使用模式匹配查找文件
有時候你可能只知道要檢索文件的部分信息,例如只知道名字或是擴展名,基于這些信息的片段,你可以正則表達式。這個檢索將會根據(jù)匹配的表達式檢索到滿足條件的文件位置,或許你要查找的文件正在其中。
下面的代碼用來在C:/rafaelnadal目錄下查找所有以jpg為擴展名的文件。這個文件會遍歷整個目錄。
import java.io.IOException;import java.nio.file.FileSystems;import java.nio.file.FileVisitOption;import java.nio.file.FileVisitResult;import java.nio.file.FileVisitor;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.PathMatcher;import java.nio.file.Paths;import java.nio.file.attribute.BasicFileAttributes;import java.util.EnumSet;class Search implements FileVisitor { private final PathMatcher matcher; public Search(String glob) { matcher = FileSystems.getDefault().getPathMatcher("glob:" + glob); } void search(Path file) throws IOException { Path name = file.getFileName(); if (name != null && matcher.matches(name)) { System.out.println("Searched file was found: " + name + " in " + file.toRealPath().toString()); } } @Override public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException { System.out.println("Visited: " + (Path) dir); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException { search((Path) file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException { //report an error if necessary return FileVisitResult.CONTINUE; }}class Main { public static void main(String[] args) throws IOException { String glob = "*.jpg"; Path fileTree = Paths.get("C:/rafaelnadal/"); Search walk = new Search(glob); EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); Files.walkFileTree(fileTree, opts, Integer.MAX_VALUE, walk); }}
如果你還知道要查找的文件其他信息,你可以創(chuàng)建一個復(fù)雜的檢索。例如,除了知道文件的名字和類型,你還知道文件大概小于多少KB,或許是文件的創(chuàng)建日期,修改日期,是否是隱藏文件或只讀,誰擁有它。下面的代碼演示查找所有擴展名為jpg并且文件小于100KB的文件。
import java.io.IOException;import java.nio.file.FileSystems;import java.nio.file.FileVisitOption;import java.nio.file.FileVisitResult;import java.nio.file.FileVisitor;import java.nio.file.Files;import java.nio.file.Path;import java.nio.file.PathMatcher;import java.nio.file.Paths;import java.nio.file.attribute.BasicFileAttributes;import java.util.EnumSet;class Search implements FileVisitor { private final PathMatcher matcher; private final long accepted_size; public Search(String glob, long accepted_size) { matcher = FileSystems.getDefault().getPathMatcher("glob:" + glob); this.accepted_size = accepted_size; } void search(Path file) throws IOException { Path name = file.getFileName(); long size = (Long) Files.getAttribute(file, "basic:size"); if (name != null && matcher.matches(name) && size <= accepted_size) { System.out.println("Searched file was found: " + name + " in " + file.toRealPath().toString() + " size (bytes):" + size); } } @Override public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException { System.out.println("Visited: " + (Path) dir); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException { search((Path) file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException { //report an error if necessary return FileVisitResult.CONTINUE; }}class Main { public static void main(String[] args) throws IOException { String glob = "*.jpg"; long size = 102400; //100 kilobytes in bytes Path fileTree = Paths.get("C:/rafaelnadal/"); Search walk = new Search(glob, size); EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); Files.walkFileTree(fileTree, opts, Integer.MAX_VALUE, walk); }}
根據(jù)文件里的內(nèi)容查找文件
其中一種比較高級的搜索文件的方式是個根據(jù)文件中的內(nèi)容。你可以傳遞一個字符序列或是一段句子,然后返回這包含這些內(nèi)容的文件。這種方式也也是最耗時的,因為他要進入每個文件里面,這就意味著要先打開文件,讀取,最后關(guān)閉它。此外,這里有很多文件格式來支持文本,例如,pdf,Microsoft Word, Excel,Powerpoint,簡單文本, xml, HTML, XHTML等等。每一種格式的讀取方式不盡相同。
接下來我們會開發(fā)一個程序用你來根據(jù)傳遞的字符串內(nèi)容來搜索文件,這個傳遞的字符串里的序列以逗號分隔, 例如:Rafael Nadal,tennis,winner of Roland Garros,BNP Paribas tournament draws。 使用StringTokenizer類,以逗號為分隔符,下面的例子就是提取每個單詞或句子放入ArrayList中。
… String words="Rafael Nadal,tennis,winner of Roland Garros,BNP Paribas tournament draws"; ArrayList<String> wordsarray = new ArrayList<>(); … StringTokenizer st = new StringTokenizer(words, ","); while (st.hasMoreTokens()) { wordsarray.add(st.nextToken()); }
下面的代碼循環(huán)ArrayList然后比較從訪問的文件中提取的比較每個單詞和句子。searchText()方法以提取的文本作為參數(shù)。
//search text private boolean searchText(String text) { boolean flag = false; for (int j = 0; j < wordsarray.size(); j++) { if ((text.toLowerCase()).contains(wordsarray.get(j).toLowerCase())) { flag = true; break; } } return flag; }
下面的例子根據(jù)不同的格式來搜索文本。不要重新造輪子,所以我們使用第三方的類庫來實現(xiàn)這些功能。
在PDF文件中搜索
對于讀取PDF文件,我們將使用兩個非常流行的開源類庫:iText(http://itextpdf.com/
) 和 Apache PDFBox(http://pdfbox.apache.org/
)。
基于iText文檔,下面的方法用來從pdf中提取文本。第一步包括創(chuàng)建一個PdfReader訪問文件,接著通過提取出PDF的頁數(shù),從每個頁面中提取文本,提取的文本傳遞給searchText()方法。如果在提取的文本中找到一token。則停止在當前文件檢索,該文件被認為是一個有效的搜索結(jié)果,及其存儲路徑和名稱我們可以打印出來后,整個搜索結(jié)束。
//search in PDF files using iText library boolean searchInPDF_iText(String file) { PdfReader reader = null; boolean flag = false; try { reader = new PdfReader(file); int n = reader.getNumberOfPages(); OUTERMOST: for (int i = 1; i <= n; i++) { String str = PdfTextExtractor.getTextFromPage(reader, i); flag = searchText(str); if (flag) { break OUTERMOST; } } } catch (Exception e) { } finally { if (reader != null) { reader.close(); } return flag; } }
如果你對PDFBox更加熟悉,你可以使用下面的方法。通過PDFParser 類創(chuàng)建PDF文件,然后提取出文件的頁數(shù),并完成通過searchText()方法提取每一頁的文本。
boolean searchInPDF_PDFBox(String file) { PDFParser parser = null; String parsedText = null; PDFTextStripper pdfStripper = null; PDDocument pdDoc = null; COSDocument cosDoc = null; boolean flag = false; int page = 0; File pdf = new File(file); try { parser = new PDFParser(new FileInputStream(pdf)); parser.parse(); cosDoc = parser.getDocument(); pdfStripper = new PDFTextStripper(); pdDoc = new PDDocument(cosDoc); OUTERMOST: while (page < pdDoc.getNumberOfPages()) { page++; pdfStripper.setStartPage(page); pdfStripper.setEndPage(page + 1); parsedText = pdfStripper.getText(pdDoc); flag = searchText(parsedText); if (flag) { break OUTERMOST; } } } catch (Exception e) { } finally { try { if (cosDoc != null) { cosDoc.close(); } if (pdDoc != null) { pdDoc.close(); } } catch (Exception e) {} return flag; } }
在Microsoft的Word,Excel和PowerPoint中查找
微軟的辦公套裝軟件文件可以使用Apache POI(http://poi.apache.org/
)類庫來操作。下面的例子使用版本3.7,基于開發(fā)指南,從word中查找字符串的例子。
boolean searchInWord(String file) { POIFSFileSystem fs = null; boolean flag = false; try { fs = new POIFSFileSystem(new FileInputStream(file)); HWPFDocument doc = new HWPFDocument(fs); WordExtractor we = new WordExtractor(doc); String[] paragraphs = we.getParagraphText(); OUTERMOST: for (int i = 0; i < paragraphs.length; i++) { flag = searchText(paragraphs[i]); if (flag) { break OUTERMOST; } } } catch (Exception e) { } finally { return flag; } }
我們從下面的例子中從Excel文本里提取文本。通過HSSFWorkbook創(chuàng)建excel文檔,先遍歷每個sheet頁,然后是逐行,最后每個單元格。
boolean searchInExcel(String file) { Row row; Cell cell; String text; boolean flag = false; InputStream xls = null; try { xls = new FileInputStream(file); HSSFWorkbook wb = new HSSFWorkbook(xls); int sheets = wb.getNumberOfSheets(); OUTERMOST: for (int i = 0; i < sheets; i++) { HSSFSheet sheet = wb.getSheetAt(i); Iterator<Row> row_iterator = sheet.rowIterator(); while (row_iterator.hasNext()) { row = (Row) row_iterator.next(); Iterator<Cell> cell_iterator = row.cellIterator(); while (cell_iterator.hasNext()) { cell = cell_iterator.next(); int type = cell.getCellType(); if (type == HSSFCell.CELL_TYPE_STRING) { text = cell.getStringCellValue(); flag = searchText(text); if (flag) { break OUTERMOST; } } } } } } catch (IOException e) { } finally { try { if (xls != null) { xls.close(); } } catch (IOException e) {} return flag; } }
最后我們可以使用下面的代碼從PowerPoint中提取文本。
boolean searchInPPT(String file) { boolean flag = false; InputStream fis = null; String text; try { fis = new FileInputStream(new File(file)); POIFSFileSystem fs = new POIFSFileSystem(fis); HSLFSlideShow show = new HSLFSlideShow(fs); SlideShow ss = new SlideShow(show); Slide[] slides = ss.getSlides(); OUTERMOST: for (int i = 0; i < slides.length; i++) { TextRun[] runs = slides[i].getTextRuns(); for (int j = 0; j < runs.length; j++) { TextRun run = runs[j]; if (run.getRunType() == TextHeaderAtom.TITLE_TYPE) { text = run.getText(); } else { text = run.getRunType() + " " + run.getText(); } flag = searchText(text); if (flag) { break OUTERMOST; } } Notes notes = slides[i].getNotesSheet(); if (notes != null) { runs = notes.getTextRuns(); for (int j = 0; j < runs.length; j++) { text = runs[j].getText(); flag = searchText(text); if (flag) { break OUTERMOST; } } } } } catch (IOException e) { } finally { try { if (fis != null) { fis.close(); } } catch (IOException e) {} return flag; } }
此外還有很多其他第三方優(yōu)秀的類庫,上面的例子在處理一些檢索時不一定是最高效的。或許可以使用Apache Lucene(http://lucene.apache.org/java/docs/index.html)來獲取很高的方式來處理。
在文本文件中搜索
文本文件(.txt
, .html
, .xml 等)
不需要第三方的類庫,它們完全可以使用NOI.2 的技術(shù)來實現(xiàn):
boolean searchInText(Path file) { boolean flag = false; Charset charset = Charset.forName("UTF-8"); try (BufferedReader reader = Files.newBufferedReader(file, charset)) { String line = null; OUTERMOST: while ((line = reader.readLine()) != null) { flag = searchText(line); if (flag) { break OUTERMOST; } } } catch (IOException e) { } finally { return flag; } }
寫一個完整的檢索程序
import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.parser.PdfTextExtractor; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; import java.nio.file.FileVisitResult; import java.nio.file.FileVisitor; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.EnumSet; import java.util.Iterator; import java.util.StringTokenizer; import org.apache.pdfbox.cos.COSDocument; import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.util.PDFTextStripper; import org.apache.poi.hslf.HSLFSlideShow; import org.apache.poi.hslf.model.Notes; import org.apache.poi.hslf.model.Slide; import org.apache.poi.hslf.model.TextRun; import org.apache.poi.hslf.record.TextHeaderAtom; import org.apache.poi.hslf.usermodel.SlideShow; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.extractor.WordExtractor; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; class Search implements FileVisitor { ArrayList<String> wordsarray = new ArrayList<>(); ArrayList<String> documents = new ArrayList<>(); boolean found = false; public Search(String words) { wordsarray.clear(); documents.clear(); StringTokenizer st = new StringTokenizer(words, ","); while (st.hasMoreTokens()) { wordsarray.add(st.nextToken().trim()); } } void search(Path file) throws IOException { found = false; String name = file.getFileName().toString(); int mid = name.lastIndexOf("."); String ext = name.substring(mid + 1, name.length()); if (ext.equalsIgnoreCase("pdf")) { found = searchInPDF_iText(file.toString()); if (!found) { found = searchInPDF_PDFBox(file.toString()); } } if (ext.equalsIgnoreCase("doc") || ext.equalsIgnoreCase("docx")) { found = searchInWord(file.toString()); } if (ext.equalsIgnoreCase("ppt")) { searchInPPT(file.toString()); } if (ext.equalsIgnoreCase("xls")) { searchInExcel(file.toString()); } if ((ext.equalsIgnoreCase("txt")) || (ext.equalsIgnoreCase("xml") || ext.equalsIgnoreCase("html")) || ext.equalsIgnoreCase("htm") || ext.equalsIgnoreCase("xhtml") || ext.equalsIgnoreCase("rtf")) { searchInText(file); } if (found) { documents.add(file.toString()); } } //search in text files boolean searchInText(Path file) { boolean flag = false; Charset charset = Charset.forName("UTF-8"); try (BufferedReader reader = Files.newBufferedReader(file, charset)) { String line = null; OUTERMOST: while ((line = reader.readLine()) != null) { flag = searchText(line); if (flag) { break OUTERMOST; } } } catch (IOException e) { } finally { return flag; } } //search in Excel files boolean searchInExcel(String file) { Row row; Cell cell; String text; boolean flag = false; InputStream xls = null; try { xls = new FileInputStream(file); HSSFWorkbook wb = new HSSFWorkbook(xls); int sheets = wb.getNumberOfSheets(); OUTERMOST: for (int i = 0; i < sheets; i++) { HSSFSheet sheet = wb.getSheetAt(i); Iterator<Row> row_iterator = sheet.rowIterator(); while (row_iterator.hasNext()) { row = (Row) row_iterator.next(); Iterator<Cell> cell_iterator = row.cellIterator(); while (cell_iterator.hasNext()) { cell = cell_iterator.next(); int type = cell.getCellType(); if (type == HSSFCell.CELL_TYPE_STRING) { text = cell.getStringCellValue(); flag = searchText(text); if (flag) { break OUTERMOST; } } } } } } catch (IOException e) { } finally { try { if (xls != null) { xls.close(); } } catch (IOException e) { } return flag; } } //search in PowerPoint files boolean searchInPPT(String file) { boolean flag = false; InputStream fis = null; String text; try { fis = new FileInputStream(new File(file)); POIFSFileSystem fs = new POIFSFileSystem(fis); HSLFSlideShow show = new HSLFSlideShow(fs); SlideShow ss = new SlideShow(show); Slide[] slides = ss.getSlides(); OUTERMOST: for (int i = 0; i < slides.length; i++) { TextRun[] runs = slides[i].getTextRuns(); for (int j = 0; j < runs.length; j++) { TextRun run = runs[j]; if (run.getRunType() == TextHeaderAtom.TITLE_TYPE) { text = run.getText(); } else { text = run.getRunType() + " " + run.getText(); } flag = searchText(text); if (flag) { break OUTERMOST; } } Notes notes = slides[i].getNotesSheet(); if (notes != null) { runs = notes.getTextRuns(); for (int j = 0; j < runs.length; j++) { text = runs[j].getText(); flag = searchText(text); if (flag) { break OUTERMOST; } } } } } catch (IOException e) { } finally { try { if (fis != null) { fis.close(); } } catch (IOException e) { } return flag; } } //search in Word files boolean searchInWord(String file) { POIFSFileSystem fs = null; boolean flag = false; try { fs = new POIFSFileSystem(new FileInputStream(file)); HWPFDocument doc = new HWPFDocument(fs); WordExtractor we = new WordExtractor(doc); String[] paragraphs = we.getParagraphText(); OUTERMOST: for (int i = 0; i < paragraphs.length; i++) { flag = searchText(paragraphs[i]); if (flag) { break OUTERMOST; } } } catch (Exception e) { } finally { return flag; } } //search in PDF files using PDFBox library boolean searchInPDF_PDFBox(String file) { PDFParser parser = null; String parsedText = null; PDFTextStripper pdfStripper = null; PDDocument pdDoc = null; COSDocument cosDoc = null; boolean flag = false; int page = 0; File pdf = new File(file); try { parser = new PDFParser(new FileInputStream(pdf)); parser.parse(); cosDoc = parser.getDocument(); pdfStripper = new PDFTextStripper(); pdDoc = new PDDocument(cosDoc); OUTERMOST: while (page < pdDoc.getNumberOfPages()) { page++; pdfStripper.setStartPage(page); pdfStripper.setEndPage(page + 1); parsedText = pdfStripper.getText(pdDoc); flag = searchText(parsedText); if (flag) { break OUTERMOST; } } } catch (Exception e) { } finally { try { if (cosDoc != null) { cosDoc.close(); } if (pdDoc != null) { pdDoc.close(); } } catch (Exception e) { } return flag; } } //search in PDF files using iText library boolean searchInPDF_iText(String file) { PdfReader reader = null; boolean flag = false; try { reader = new PdfReader(file); int n = reader.getNumberOfPages(); OUTERMOST: for (int i = 1; i <= n; i++) { String str = PdfTextExtractor.getTextFromPage(reader, i); flag = searchText(str); if (flag) { break OUTERMOST; } } } catch (Exception e) { } finally { if (reader != null) { reader.close(); } return flag; } } //search text private boolean searchText(String text) { boolean flag = false; for (int j = 0; j < wordsarray.size(); j++) { if ((text.toLowerCase()).contains(wordsarray.get(j).toLowerCase())) { flag = true; break; } } return flag; } @Override public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException { System.out.println("Visited: " + (Path) dir); return FileVisitResult.CONTINUE; } @Override public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException { return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException { search((Path) file); return FileVisitResult.CONTINUE; } @Override public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException { //report an error if necessary return FileVisitResult.CONTINUE; } } class Main { public static void main(String[] args) throws IOException { String words = "Rafael Nadal, tennis, winner of Roland Garros, BNP Paribas tournament draws"; Search walk = new Search(words); EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories(); for (Path root : dirs) { Files.walkFileTree(root, opts, Integer.MAX_VALUE, walk); } System.out.println("____________________________________________________________"); for(String path_string: walk.documents){ System.out.println(path_string); } System.out.println("____________________________________________________________"); } }
需要注意的是,有些時候程序處理的很慢,這主要取決于文件大小,要檢查的文件的個數(shù),目錄的層級深度。此外你可以繼續(xù)完善這個程序,例如支持更多地格式,增加進度條來顯示處理的狀態(tài),使用多線程加快查找速度。
新聞熱點
疑難解答