Java tutorial
/* * Copyright (c) 2018 Nuvolect LLC. * This software is offered for free under conditions of the GPLv3 open source software license. * Contact Nuvolect LLC for a less restrictive commercial license if you would like to use the software * without the GPLv3 restrictions. */ package com.nuvolect.deepdive.util; import android.content.Context; import com.nuvolect.deepdive.webserver.MimeUtil; import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.json.JSONException; import org.json.JSONObject; import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; /** * Various utility methods to operate with Omni files. */ public class OmniUtil { public static InputStream getFileInputStream(OmniFile request) { try { if (request.isCryp()) return new info.guardianproject.iocipher.FileInputStream(request.getCryFile()); else return new java.io.FileInputStream(request.getStdFile()); } catch (FileNotFoundException e) { e.printStackTrace(); } return null; } /** * Return a file from a uri containing a hashed file path. * File may be null if the uri or hash is improperly formed. * @param uri * @return */ public static OmniFile getFileFromUri(String uri) { String uriSegments[] = uri.split("/"); if (uriSegments.length == 0) return null; return new OmniFile(uriSegments[1]); } /** * Return the file of a managed volume object. * * @param hash * @return */ public static OmniFile getFileFromHash(String hash) { if (hash.startsWith("/")) hash = hash.substring(1); String segments[] = hash.split("_"); String volumeId = segments[0]; String path = OmniHash.decode(segments[1]); OmniFile targetFile = new OmniFile(volumeId, path); return targetFile; } /** * Create a file of a specific size. Works with all file types. * @param file * @param size * @throws IOException */ public static void createFile(OmniFile file, long size) throws IOException { OutputStream out = file.getOutputStream(); byte[] buffer = new byte[1024 * 8];// IOCipher works best with 8K blocks long progress = 0; int count = buffer.length; while (progress < size) { out.write(buffer, 0, count); progress += count; } out.close(); } public static long countBytes(OmniFile file) throws IOException { InputStream in = file.getFileInputStream(); long count = 0; byte[] buffer = new byte[1024 * 8];// IOCipher works best with 8K blocks int read; while ((read = in.read(buffer)) != -1) { count += read; } in.close(); return count; } public static String getTimeDateFilename(String extension) { String filename = "mm" + new SimpleDateFormat("yyMMddHHmmss").format(new Date()) + extension; filename = filename.replaceAll(" ", ""); return filename; } public static String getFilesystemStatus(OmniFile file) { long freeSpace = file.getFreeSpace(); long totalSpace = file.getTotalSpace(); // String s = "Free " + humanReadableByteCount(freeSpace, true) + " of " + humanReadableByteCount(totalSpace, true); return s; } public static String humanReadableByteCount(long bytes, boolean si) { int unit = si ? 1000 : 1024; if (bytes < unit) return bytes + " B"; int exp = (int) (Math.log(bytes) / Math.log(unit)); String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); } /** * Return a unique file given the current file as a model. * Example if file exists: /Picture/mypic.jpg > /Picture/mypic~.jpg * @return */ public static OmniFile makeUniqueName(OmniFile initialFile) { String path = initialFile.getPath(); String basePath = FilenameUtils.getFullPath(path); // path without name String baseName = FilenameUtils.getBaseName(path); // name without extension String extension = FilenameUtils.getExtension(path); // extension String volumeId = initialFile.getVolumeId(); String dot = "."; if (extension.isEmpty()) dot = ""; OmniFile file = initialFile; while (file.exists()) { baseName += "~"; String fullPath = basePath + baseName + dot + extension; file = new OmniFile(volumeId, fullPath); } return file; } /** * Get a Omni style relative path given a volume ID and an absolute path. * @param volumeId * @param absolutePath * @return relative Omni path. */ public static String getShortPath(String volumeId, String absolutePath) { String root = Omni.getRoot(volumeId); String absPath = (absolutePath + "/").replace("//", "/"); return StringUtils.replaceOnce(absPath, root, "/"); } /** * Recursively deletes a directory and its contents. * Note only the last success case is returned. * * @param f The directory (or file) to delete * @return true if the delete succeeded, false otherwise */ public static int deleteRecursive(Context ctx, OmniFile f) { return deleteRecursive(ctx, f, 0); } private static int deleteRecursive(Context ctx, OmniFile f, int count) { if (count == -1) return -1; if (f.isDirectory()) { for (OmniFile child : f.listFiles()) { if (-1 == deleteRecursive(ctx, child, count)) { return (-1); } } } /** * Delete thumbnail, if there is one */ OmniImage.deleteThumbnail(f); boolean success = f.delete(); /** * The crypto storage does not use the media scanner. */ //TODO cleanup //TODO consider role of a media scanner and lucene file management // if( success && f.isStd()) // MediaScannerConnection.scanFile( // ctx, // new String[]{f.getAbsolutePath()}, // null, // null); return success ? ++count : -1; } /** * Makes a directory, including any necessary but nonexistent parent * directories. If a file already exists with specified name but it is * not a directory then an IOException is thrown. * If the directory cannot be created (or does not already exist) * then an IOException is thrown. * * @param directory directory to create, must not be {@code null} * @return true if directory is created * @throws NullPointerException if the directory is {@code null} * @throws IOException if the directory cannot be created or the file already exists but is not a directory */ public static boolean forceMkdir(final OmniFile directory) throws IOException { boolean directoryCreated = false; if (directory.exists()) { if (!directory.isDirectory()) { final String message = "File " + directory + " exists and is " + "not a directory. Unable to create directory."; throw new IOException(message); } } else { directoryCreated = directory.mkdirs(); if (!directoryCreated) { // Double-check that some other thread or process hasn't made // the directory in the background if (!directory.isDirectory()) { final String message = "Unable to create directory " + directory; throw new IOException(message); } } } return directoryCreated; } /** * Makes any necessary but nonexistent parent directories for a given File. If the parent directory cannot be * created then an IOException is thrown. * * @param file file with parent to create, must not be {@code null} * @throws NullPointerException if the file is {@code null} * @throws IOException if the parent directory cannot be created * @since 2.5 */ public static boolean forceMkdirParent(final OmniFile file) throws IOException { final OmniFile parent = file.getParentFile(); if (parent == null) { return false; } return forceMkdir(parent); } public static boolean writeFile(OmniFile file, String fileContents) { boolean success = true; try { OutputStream out = null; OmniUtil.forceMkdirParent(file); out = new BufferedOutputStream(new FileOutputStream(file.getStdFile())); out.write(fileContents.getBytes()); if (out != null) out.close(); } catch (IOException e) { LogUtil.log(OmniUtil.class, "File write failed: " + e.toString()); success = false; } return success; } /** * Return the contents of a text file. Upon error return feedback to the user * in the file_content field. If the volumeId is empty, use the default volumeId. * @param volumeId volume of the file * @param path path, relative to the volume * @return */ public static JSONObject getText(String volumeId, String path) { String file_ext = FilenameUtils.getExtension(path); boolean isText = MimeUtil.isText(file_ext); String file_content = ""; if (volumeId.isEmpty()) volumeId = Omni.getDefaultVolumeId(); OmniFile omniFile = new OmniFile(volumeId, path); if (!omniFile.exists()) file_content = "File does not exist: " + path; else if (omniFile.isDirectory()) file_content = "File is a directory: " + path; else if (!isText) file_content = "File is binary: " + path; else { file_content = FileUtil.readFile(omniFile.getStdFile()); } JSONObject wrapper = new JSONObject(); try { wrapper.put("file_name", omniFile.getName()); wrapper.put("file_content", file_content); wrapper.put("file_path", path); } catch (JSONException e) { e.printStackTrace(); } return wrapper; } /** * Copy a file from assets to an omni destination folder. * @param ctx * @param assetFilePath * @param destinationFile * @return number of bytes copied * @throws IOException */ public static int copyAsset(Context ctx, String assetFilePath, OmniFile destinationFile) throws IOException { InputStream inputStream = ctx.getAssets().open(assetFilePath); OutputStream outputStream = destinationFile.getOutputStream(); int numBytes = IOUtils.copy(inputStream, outputStream); inputStream.close(); outputStream.close(); return numBytes; } }