package parser.utils; import java.io.*; import java.nio.charset.Charset; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; /** * 文件类型检测器 * * @author lai */ public final class FileTypesDetector { /** * 将文件头转换成16进制字符串 * * @param src File bytes * @return 16进制字符串 */ private static String bytesToHexString(byte[] src) { StringBuilder stringBuilder = new StringBuilder(); if (src == null || src.length <= 0) { return null; } //for (int i = 0; i < src.length; i++) { for (byte aSrc : src) { int v = aSrc & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } return stringBuilder.toString().toUpperCase(); } private static String isTextFile(InputStream inputStream) throws IOException { int len = 180; int off = 0; if (inputStream.available() < 180) { len = inputStream.available(); } byte[] byteArr = new byte[len]; int total = inputStream.read(byteArr, off, len); // System.out.println(total + " - isTextFile()"); if (Charset.forName("US-ASCII").newEncoder().canEncode(new String(byteArr))) { // System.out.println("US-ASCII"); return "US-ASCII text"; } if (Charset.forName("ISO-8859-1").newEncoder().canEncode(new String(byteArr))) { // System.out.println("ISO-8859-1"); return "US-ASCII text"; } if (Charset.forName("GB2312").newEncoder().canEncode(new String(byteArr))) { // System.out.println("GB2312"); return "GB2312 text"; } // if (Charset.forName("GB18030").newEncoder().canEncode(new String(byteArr))) { // System.out.println("GB18030"); // return "GB18030 text"; // } // if (Charset.forName("HZ").newEncoder().canEncode(new String(byteArr))) { // System.out.println("HZ"); // return "HZ text"; // } if (Charset.forName("BIG5").newEncoder().canEncode(new String(byteArr))) { // System.out.println("BIG5"); return "BIG5 text"; } /* int counter = 0; int flag = 0; for (byte b : byteArr) { if (counter % 10 == 0) { System.out.println(); } System.out.print(b + "\t"); // 判断有没有char(0)字符。 // 二进制文件基本上都会有char(0),注意,是“基本上” 。 if (b == 0) { if (flag == 0) { flag = 1; } else { return null; } } if (b != 0 && flag == 1) { flag = 0; } // if (b > 0 && flag == 1) { // System.out.println("\n"); // return null; // } counter++; } System.out.println("\n"); */ return "text"; } /** * @param begin off * @param offset offset * @param inputStream inputStream * @return String * @throws IOException */ private static String readOffset(int begin, int offset, InputStream inputStream) throws IOException { // System.out.println(inputStream.markSupported()); byte[] b = new byte[offset]; inputStream.skip(begin); int total = inputStream.read(b, 0, offset); // System.out.println(total + "readOffset"); if (total == -1) { return null; } return new String(b); } /** * 判断文件类型 * * @param is 文件 * @return 文件类型 */ public static String getType(InputStream is) throws IOException { int len = 100; int off = 0; if (is.available() <= 0) { return "Empty File"; } if (is.available() < 100) { len = is.available(); } InputStream inputStream; if (!is.markSupported()) { inputStream = new BufferedInputStream(is); } else { inputStream = is; } inputStream.mark(len); String fileHead; byte[] bytesArr = new byte[len]; int total = inputStream.read(bytesArr, off, len); if (total != -1) { fileHead = bytesToHexString(bytesArr); // System.out.println(fileHead); } else { return null; } if (fileHead == null || fileHead.length() == 0) { return null; } FileType[] fileTypes = FileType.values(); for (FileType type : fileTypes) { if (fileHead.startsWith(type.getValue())) { return type.toString(); // if (type.toString().equals("ZIP")) { // if (fileHead.startsWith("504B0304140008000800")) { // return "APK"; // } // inputStream.reset(); // String str = FileTypesDetector.readOffset(off, len, inputStream); // inputStream.reset(); // System.out.println(str); // if (str.contains("META-INF/MANIFEST.MF") || str.contains("res/") || str.contains("classes.dex")) // return "APK"; // return type.toString(); // } else { // return type.toString(); // } } } inputStream.reset(); String txt = isTextFile(inputStream); inputStream.close(); if (txt != null) { return txt; } if (fileHead.startsWith("FFF")) { return "AUDIO_FILE"; } return "DATA"; } /** * 判断文件类型 * * @param filePath 文件路径 * @return 文件类型 */ public static String getType(String filePath) throws IOException { BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(filePath)); return getType(inputStream); } public static boolean isAPK(InputStream inputStream) { ZipInputStream zipInputStream = new ZipInputStream(inputStream); ZipEntry entry; try { while (true) { entry = zipInputStream.getNextEntry(); if (entry == null) { break; } if (entry.getName().equals("classes.dex")) { return true; } } } catch (ZipException e) { System.out.println("It's a encrypted ZIP."); return false; } catch (IOException e) { e.printStackTrace(); return false; } finally { try { zipInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } return false; } /** * 判断文件是否为 APK 文件 * * @param pFile 文件 * @return 为APK文件返回 true, 否则, 返回false. */ public static boolean isAPK(File pFile) { String fileType; try { fileType = FileTypesDetector.getType(pFile.getAbsolutePath()); } catch (IOException e) { System.out.println(e.getLocalizedMessage()); return false; } if (!fileType.equals("ZIP") && !fileType.equals("APK")) { return false; } ZipFile zipFile = null; try { zipFile = new ZipFile(pFile); ZipEntry zipEntry = zipFile.getEntry("classes.dex"); return zipEntry != null; } catch (IOException e) { return false; } finally { if (zipFile != null) { try { zipFile.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 判断文件是否为 SIS 文件 * * @param pFile 文件 * @return 为APK文件返回 true, 否则, 返回false. */ public static boolean isSIS(File pFile) { String fileType; try { fileType = FileTypesDetector.getType(pFile.getAbsolutePath()); } catch (IOException e) { return false; } return fileType.contains("SIS"); } public static boolean isDEX(File pFile) { String fileType; try { fileType = FileTypesDetector.getType(pFile.getAbsolutePath()); } catch (IOException e) { return false; } return fileType.contains("DEX"); } }