在實際的接口測試中,有時需要根據情況進行文件的上傳和下載。在文件數量比較小的時候,我們當然可以直接處理(比如若干個接口都用一個文件)。但是,如果我們上傳的文件需要使用不同文件夾里不同的文件,而且數量又比較大的情況下,直接寫路徑就比較麻煩了。
那么,怎樣來處理這樣的問題呢?還是需要先整理一下思路。
首先,我們需要根據某些特征,找到這些文件。例如,我們可以在指定的文件夾下面,按照文件后綴名來找尋文件。通常,我們在DOS下查詢該文件夾下尋找同一后綴名文件的時候,會使用通配符“*”來代替文件名,例如:*.jpg,*.xls等等。那么,我們可以指定一個文件夾,然后使用將通配符變為正則的方式,來匹配查找文件。
另外,如果在我們指定的文件夾中,存在子文件夾的情況,我們需要進行遞歸處理。即,進入子文件夾后,再次對子文件夾下的對象進行遍歷,以此類推。
先來看一段代碼:
private static String generatePattern(String fileConf) { fileConf = fileConf.trim(); // 根據配置生成正確的正則 fileConf = fileConf.replace('*', '#'); // 將*號之前加上. fileConf = fileConf.replaceAll("#", ".*"); return fileConf; }
這里,我們定義了一個生成正則的方法。就是將"*.XXX"變成“.*.XXX”(仔細看,就是在之前加了一個".")。我們可以利用這個正則表達式來匹配我們想要尋找的文件。
接下來,我們來看一下遞歸查找的問題。首先,我們需要定義一個要查找的文件夾。而在java中,我們可以直接定義一個主路徑作為file的對象。
例如:
String c = "k:/abc/"; File file = new File(c);
這樣的話,可以使用getName()方法獲取文件或文件夾的名稱(不包含上級路徑)。另外,也可以使用listFiles() 返回目錄下的文件或者目錄對象(File類實例),包含隱藏文件。當然,對於文件,這樣操作會返回null。
下面,我們來看一下遞歸的操作。思路是這樣的:
1.判斷當前的file對象是文件還是文件夾
2.如果是文件,若匹配正則,則將文件加入list。
3.如果是文件夾,則獲取該文件夾下面所有的文件或者目錄對象,若匹配正則,則將文件加入list。
private static ArrayList<File> filePattern(File file, Pattern p) { if (file == null) { return null; } // 如果是文件,則加入fileList if (file.isFile()) { Matcher fMatcher = p.matcher(file.getName()); if (fMatcher.matches()) { ArrayList<File> list = new ArrayList<File>(); list.add(file); return list; } // 如果是目錄,則進行遞歸查找 } else if (file.isDirectory()) { File[] files = file.listFiles(); if (files != null && files.length > 0) { ArrayList<File> list = new ArrayList<File>(); for (File f : files) { //此處進行遞歸 ArrayList<File> rlist = filePattern(f, p); if (rlist != null) { //將查找結果都加入fileList list.addAll(rlist); } } return list; } } return null; }
那么,根據上面的代碼,我們可以將路徑下所有的匹配正則的文件都找到,並放入fileList中。
接下來,我們來定義一個方法,使用主路徑以及通配符作為參數,來進行文件的查找。在通配符參數的指定中,我們使用“;”來進行分隔,來找到我們所需要的文件。
例如:
String dirs = "k:/abc/";
String file_con = "*.doc;*.xls";
這里會出現一個新的問題,如果我按照上面所寫,會把“k:/abc/”下的所有匹配的文件都找出來。
假如,我是需要尋找主路經下test1文件夾下的*.doc,和test2文件夾下的*.xls怎么辦?
這里在指定參數的部分,我們需要對文件夾作出判斷,即對最后一個“/”進行分隔處理。
請看下面一段代碼:
public static List<File> getFilesByConf(String dir, String fileConf) { String[] fileConfArr = fileConf.split(";");// 多個配置‘;’分開 List<File> list = new ArrayList<File>(); if (fileConfArr != null && fileConfArr.length > 0) { for (String conftemp : fileConfArr) { int at = conftemp.lastIndexOf("/"); File file = null; String fileContextPath = ""; // 絕對目錄路徑 String contextPath = dir; // 針對目錄部分的處理 if (at > 0) { fileContextPath = fileConf.substring(0, at); } if (StringUtil.isNotEmpty(fileContextPath)) { contextPath = contextPath + fileContextPath; } file = new File(contextPath); String fileNameConf = conftemp.substring(at + 1,conftemp.length());// 文件名配置 String fileConfTemp = generatePattern(fileNameConf); Pattern p = Pattern.compile(fileConfTemp); ArrayList<File> listtemp = filePattern(file, p); list.addAll(listtemp); } } return removeDuplicate(list);// 去重 }
這里,我們就完成了針對路徑的處理。順便說一下,這里的去重,使用的是利用HashSet的特性來進行去重。
public static List removeDuplicate(List list) { if (list == null) { return null; } Set set = new HashSet(); List newList = new ArrayList(); for (Iterator iter = list.iterator(); iter.hasNext();) { Object obj = iter.next(); if (set.add(obj)) { newList.add(obj); } } return newList; }
至此,我們就完成了對於文件查找的處理。
總結一下,我們只需要提供兩個參數,一個是主路經,一個匹配的通配符的字符串參數(可以帶路徑),即可批量查找到我們所需要的文件。
接下來,我們看一下,下載文件的處理。
下載文件一般比較好處理,基本思路就是使用輸入流來寫入,然后保存即可。
需要注意的是,針對比較大的文件時,我們需要設置Buffer(即緩沖區)。不應用緩沖區的時候,每次讀取一個字節,寫入一個字節,由於操作磁盤比內存慢的很多,所以不應用緩沖區效率很低;應用緩沖區,可以一次讀取多個字節,先不寫入磁盤,而是放入內存之中,到了緩沖區大小的時候,在寫入磁盤,減少了對磁盤的操作,效率較高。
public static boolean writeFile(InputStream is, String filePath) { File file = new File(filePath); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } FileOutputStream fileout; try { fileout = new FileOutputStream(file); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } /** * 根據實際運行效果 設置緩沖區大小 */ byte[] buffer = new byte[10 * 1024]; int ch = 0; try { while ((ch = is.read(buffer)) != -1) { fileout.write(buffer, 0, ch); } return true; } catch (IOException e) { e.printStackTrace(); return false; } finally { try { is.close(); fileout.flush(); fileout.close(); } catch (IOException e) { e.printStackTrace(); } } }
這里根據實際情況,來設置緩沖區的大小。
這樣就可以根據接口返回的內容,寫入文件到指定的路徑中。