package es.um.redes.nanoFiles.util; import java.io.File; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Vector; import es.um.redes.nanoFiles.shell.NFShell; /** * @author rtitos * * Utility class with static methods to abstract handling of file * metadata, loading shared failes, search by name substring, etc. */ public class FileInfo { public String fileHash; public String fileName; public String filePath; public long fileSize = -1; public FileInfo(String hash, String name, long size, String path) { fileHash = hash; fileName = name; fileSize = size; filePath = path; } public FileInfo() { } public String toString() { StringBuffer strBuf = new StringBuffer(); strBuf.append(String.format("%1$-30s", fileName)); strBuf.append(String.format("%1$10s", fileSize)); strBuf.append(String.format(" %1$-45s", fileHash)); return strBuf.toString(); } public static void printToSysout(FileInfo[] files) { StringBuffer strBuf = new StringBuffer(); strBuf.append(String.format("%1$-30s", "Name")); strBuf.append(String.format("%1$10s", "Size")); strBuf.append(String.format(" %1$-45s", "Hash")); System.out.println(strBuf); for (FileInfo file : files) { System.out.println(file); } } /** * Scans the given directory and returns an array of FileInfo objects, one for * each file recursively found in the given folder and its subdirectories. * * @param sharedFolderPath The folder to be scanned * @return An array of file metadata (FileInfo) of all the files found */ public static FileInfo[] loadFilesFromFolder(String sharedFolderPath) { File folder = new File(sharedFolderPath); Map files = loadFileMapFromFolder(folder); FileInfo[] fileinfoarray = new FileInfo[files.size()]; Iterator itr = files.values().iterator(); int numFiles = 0; while (itr.hasNext()) { fileinfoarray[numFiles++] = itr.next(); } return fileinfoarray; } /** * Scans the given directory and returns a map of pairs. * * @param folder The folder to be scanned * @return A map of the metadata (FileInfo) of all the files recursively found * in the given folder and its subdirectories. */ protected static Map loadFileMapFromFolder(final File folder) { Map files = new HashMap(); scanFolderRecursive(folder, files); return files; } private static void scanFolderRecursive(final File folder, Map files) { if (folder.exists() == false) { System.err.println("scanFolder cannot find folder " + folder.getPath()); return; } if (folder.canRead() == false) { System.err.println("scanFolder cannot access folder " + folder.getPath()); return; } for (final File fileEntry : folder.listFiles()) { if (fileEntry.isDirectory()) { scanFolderRecursive(fileEntry, files); } else { String fileName = fileEntry.getName(); String filePath = fileEntry.getPath(); String fileHash = FileDigest.computeFileChecksumString(filePath); long fileSize = fileEntry.length(); if (fileSize > 0) { files.put(fileHash, new FileInfo(fileHash, fileName, fileSize, filePath)); } else { if (fileName.equals(NFShell.FILENAME_TEST_SHELL)) { NFShell.enableVerboseShell(); System.out.println("[Enabling verbose shell]"); } else { System.out.println("Ignoring empty file found in shared folder: " + filePath); } } } } } public static FileInfo[] lookupFilenameSubstring(FileInfo[] files, String filenameSubstr) { String needle = filenameSubstr.toLowerCase(); Vector matchingFiles = new Vector(); for (int i = 0; i < files.length; i++) { if (files[i].fileName.toLowerCase().contains(needle)) { matchingFiles.add(files[i]); } } FileInfo[] result = new FileInfo[matchingFiles.size()]; matchingFiles.toArray(result); return result; } public static FileInfo[] lookupHashSubstring(FileInfo[] files, String hashSubstr) { String needle = hashSubstr.toLowerCase(); Vector matchingFiles = new Vector(); for (int i = 0; i < files.length; i++) { if (files[i].fileHash.toLowerCase().contains(needle)) { matchingFiles.add(files[i]); } } FileInfo[] result = new FileInfo[matchingFiles.size()]; matchingFiles.toArray(result); return result; } // Serialización sencilla para enviar listas de FileInfo por TCP public static byte[] serializeList(FileInfo[] files) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeInt(files.length); for (FileInfo f : files) { oos.writeUTF(f.fileHash); oos.writeUTF(f.fileName); oos.writeLong(f.fileSize); } oos.flush(); return bos.toByteArray(); } public static FileInfo[] deserializeList(byte[] data) throws IOException { ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data)); int n = ois.readInt(); FileInfo[] files = new FileInfo[n]; for (int i = 0; i < n; i++) { String hash = ois.readUTF(); String name = ois.readUTF(); long size = ois.readLong(); files[i] = new FileInfo(hash, name, size, null); } return files; } }