Android Open Source - android-simple-storage Abstract Disk Storage






From Project

Back to project page android-simple-storage.

License

The source code is released under:

Apache License

If you think the Android project android-simple-storage listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.sromku.simple.storage;
//from w w  w .j  av  a  2  s.  co  m
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import javax.crypto.Cipher;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.StatFs;

import com.sromku.simple.storage.helpers.ImmutablePair;
import com.sromku.simple.storage.helpers.OrderType;
import com.sromku.simple.storage.helpers.SizeUnit;
import com.sromku.simple.storage.security.SecurityUtil;

/**
 * Common class for internal and external storage implementations
 * 
 * @author Roman Kushnarenko - sromku (sromku@gmail.com)
 * 
 */
abstract class AbstractDiskStorage implements Storage {
  protected static final String UTF_8 = "UTF-8";

  AbstractDiskStorage() {
  }

  protected SimpleStorageConfiguration getConfiguration() {
    return SimpleStorage.getConfiguration();
  }

  @Override
  public boolean createDirectory(String name) {
    String path = buildPath(name);

    // Check if the directory already exist
    if (isDirectoryExists(path)) {
      throw new RuntimeException("The direcory already exist. You can't override the existing one. Use createDirectory(String path, boolean override)");
    }

    File directory = new File(path);

    // Create a new directory
    boolean wasCreated = directory.mkdirs();

    return wasCreated;
  }

  @Override
  public boolean createDirectory(String name, boolean override) {
    // If override==false, then don't override
    if (!override) {
      if (isDirectoryExists(name)) {
        return true;
      } else {
        return createDirectory(name);
      }
    }

    // Check if directory exists. If yes, then delete all directory
    if (isDirectoryExists(name)) {
      deleteDirectory(name);
    }

    // Create new directory
    boolean wasCreated = createDirectory(name);
    // If directory is already exist then wasCreated=false
    if (!wasCreated) {
      throw new RuntimeException("Couldn't create new direcory");
    }

    return true;
  }

  @Override
  public boolean deleteDirectory(String name) {
    String path = buildPath(name);
    return deleteDirectoryImpl(path);
  }

  @Override
  public boolean isDirectoryExists(String name) {
    String path = buildPath(name);
    return new File(path).exists();
  }

  @Override
  public boolean createFile(String directoryName, String fileName, String content) {
    return createFile(directoryName, fileName, content.getBytes());
  }

  @Override
  public boolean createFile(String directoryName, String fileName, Storable storable) {
    return createFile(directoryName, fileName, storable.getBytes());
  }

  @Override
  public boolean createFile(String directoryName, String fileName, byte[] content) {
    String path = buildPath(directoryName, fileName);
    try {
      OutputStream stream = new FileOutputStream(new File(path));

      /*
       * Check if needs to be encrypted. If yes, then encrypt it.
       */
      if (getConfiguration().isEncrypted()) {
        content = encrypt(content, Cipher.ENCRYPT_MODE);
      }

      stream.write(content);
      stream.flush();
      stream.close();
    } catch (IOException e) {
      throw new RuntimeException("Failed to create", e);
    }
    return true;
  }

  @Override
  public boolean createFile(String directoryName, String fileName, Bitmap bitmap) {
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
    byte[] byteArray = stream.toByteArray();
    return createFile(directoryName, fileName, byteArray);
  }

  @Override
  public boolean deleteFile(String directoryName, String fileName) {
    String path = buildPath(directoryName, fileName);
    File file = new File(path);
    return file.delete();
  }

  @Override
  public boolean isFileExist(String directoryName, String fileName) {
    String path = buildPath(directoryName, fileName);
    return new File(path).exists();
  }

  @Override
  public byte[] readFile(String directoryName, String fileName) {
    String path = buildPath(directoryName, fileName);
    final FileInputStream stream;
    try {
      stream = new FileInputStream(new File(path));
      return readFile(stream);
    } catch (FileNotFoundException e) {
      throw new RuntimeException("Failed to read file to input stream", e);
    }
  }

  @Override
  public String readTextFile(String directoryName, String fileName) {
    byte[] bytes = readFile(directoryName, fileName);
    String content = new String(bytes);
    return content;
  }

  @Override
  public void appendFile(String directoryName, String fileName, String content) {
    appendFile(directoryName, fileName, content.getBytes());
  }

  @Override
  public void appendFile(String directoryName, String fileName, byte[] bytes) {
    if (!isFileExist(directoryName, fileName)) {
      throw new RuntimeException("Impossible to append content, because such file doesn't exist");
    }

    try {
      String path = buildPath(directoryName, fileName);
      FileOutputStream stream = new FileOutputStream(new File(path), true);
      stream.write(bytes);
      stream.write(System.getProperty("line.separator").getBytes());
      stream.flush();
      stream.close();
    } catch (IOException e) {
      throw new RuntimeException("Failed to append content to file", e);
    }
  }

  @Override
  public List<File> getNestedFiles(String directoryName) {
    String buildPath = buildPath(directoryName);
    File file = new File(buildPath);
    List<File> out = new ArrayList<File>();
    getDirectoryFilesImpl(file, out);
    return out;
  }

  @Override
  public List<File> getFiles(String directoryName, final String matchRegex) {
    String buildPath = buildPath(directoryName);
    File file = new File(buildPath);
    List<File> out = null;
    if (matchRegex != null) {
      FilenameFilter filter = new FilenameFilter() {
        @Override
        public boolean accept(File dir, String fileName) {
          if (fileName.matches(matchRegex)) {
            return true;
          }
          return false;
        }
      };
      out = Arrays.asList(file.listFiles(filter));
    } else {
      out = Arrays.asList(file.listFiles());
    }
    return out;
  }

  @Override
  public List<File> getFiles(String directoryName, OrderType orderType) {
    List<File> files = getFiles(directoryName, (String) null);
    Collections.sort(files, orderType.getComparator());
    return files;
  }

  @Override
  public File getFile(String name) {
    String path = buildPath(name);
    File file = new File(path);
    return file;
  }

  @Override
  public File getFile(String directoryName, String fileName) {
    String path = buildPath(directoryName, fileName);
    return new File(path);
  }

  @Override
  public void rename(File file, String newName) {
    String name = file.getName();
    String newFullName = file.getAbsolutePath().replaceAll(name, newName);
    File newFile = new File(newFullName);
    file.renameTo(newFile);
  }

  @Override
  public double getSize(File file, SizeUnit unit) {
    long length = file.length();
    return (double) length / (double) unit.inBytes();
  }
  
  @SuppressLint("NewApi")
  @SuppressWarnings("deprecation")
  @Override
  public long getFreeSpace(SizeUnit sizeUnit) {
    String path = buildAbsolutePath();
    StatFs statFs = new StatFs(path);
    long availableBlocks;
    long blockSize;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
      availableBlocks = statFs.getAvailableBlocks();
      blockSize = statFs.getBlockSize();
    } else {
      availableBlocks = statFs.getAvailableBlocksLong();
      blockSize = statFs.getBlockSizeLong();
    }
    long freeBytes = availableBlocks * blockSize;
    return freeBytes / sizeUnit.inBytes();
  }
  
  @SuppressLint("NewApi")
  @SuppressWarnings("deprecation")
  @Override
  public long getUsedSpace(SizeUnit sizeUnit) {
    String path = buildAbsolutePath();
    StatFs statFs = new StatFs(path);
    long availableBlocks;
    long blockSize;
    long totalBlocks;
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
      availableBlocks = statFs.getAvailableBlocks();
      blockSize = statFs.getBlockSize();
      totalBlocks = statFs.getBlockCount();
    } else {
      availableBlocks = statFs.getAvailableBlocksLong();
      blockSize = statFs.getBlockSizeLong();
      totalBlocks = statFs.getBlockCountLong();
    }
    long usedBytes = totalBlocks * blockSize - availableBlocks * blockSize;
    return usedBytes / sizeUnit.inBytes();
  }

  @Override
  public void copy(File file, String directoryName, String fileName) {
    if (!file.isFile()) {
      return;
    }
    
    FileInputStream inStream = null;
    FileOutputStream outStream = null;
    try {
      inStream = new FileInputStream(file);
      outStream = new FileOutputStream(new File(buildPath(directoryName, fileName)));
      FileChannel inChannel = inStream.getChannel();
      FileChannel outChannel = outStream.getChannel();
      inChannel.transferTo(0, inChannel.size(), outChannel);
    } catch (Exception e) {
      throw new StorageException(e);
    } finally {
      closeQuietly(inStream);
      closeQuietly(outStream);
    }
  }

  @Override
  public void move(File file, String directoryName, String fileName) {
    copy(file, directoryName, fileName);
    file.delete();
  }

  protected byte[] readFile(final FileInputStream stream) {
    class Reader extends Thread {
      byte[] array = null;
    }

    Reader reader = new Reader() {
      public void run() {
        LinkedList<ImmutablePair<byte[], Integer>> chunks = new LinkedList<ImmutablePair<byte[], Integer>>();

        // read the file and build chunks
        int size = 0;
        int globalSize = 0;
        do {
          try {
            int chunkSize = getConfiguration().getChuckSize();
            // read chunk
            byte[] buffer = new byte[chunkSize];
            size = stream.read(buffer, 0, chunkSize);
            if (size > 0) {
              globalSize += size;

              // add chunk to list
              chunks.add(new ImmutablePair<byte[], Integer>(buffer, size));
            }
          } catch (Exception e) {
            // very bad
          }
        } while (size > 0);

        try {
          stream.close();
        } catch (Exception e) {
          // very bad
        }

        array = new byte[globalSize];

        // append all chunks to one array
        int offset = 0;
        for (ImmutablePair<byte[], Integer> chunk : chunks) {
          // flush chunk to array
          System.arraycopy(chunk.element1, 0, array, offset, chunk.element2);
          offset += chunk.element2;
        }
      };
    };

    reader.start();
    try {
      reader.join();
    } catch (InterruptedException e) {
      throw new RuntimeException("Failed on reading file from storage while the locking Thread", e);
    }

    if (getConfiguration().isEncrypted()) {
      return encrypt(reader.array, Cipher.DECRYPT_MODE);
    } else {
      return reader.array;
    }
  }

  protected abstract String buildAbsolutePath();
  
  protected abstract String buildPath(String name);

  protected abstract String buildPath(String directoryName, String fileName);

  /**
   * Encrypt or Descrypt the content. <br>
   * 
   * @param content
   *            The content to encrypt or descrypt.
   * @param encryptionMode
   *            Use: {@link Cipher#ENCRYPT_MODE} or
   *            {@link Cipher#DECRYPT_MODE}
   * @return
   */
  protected synchronized byte[] encrypt(byte[] content, int encryptionMode) {
    final byte[] secretKey = getConfiguration().getSecretKey();
    final byte[] ivx = getConfiguration().getIvParameter();
    return SecurityUtil.encrypt(content, encryptionMode, secretKey, ivx);
  }

  /**
   * Delete the directory and all sub content.
   * 
   * @param path
   *            The absolute directory path. For example:
   *            <i>mnt/sdcard/NewFolder/</i>.
   * @return <code>True</code> if the directory was deleted, otherwise return
   *         <code>False</code>
   */
  private boolean deleteDirectoryImpl(String path) {
    File directory = new File(path);

    // If the directory exists then delete
    if (directory.exists()) {
      File[] files = directory.listFiles();
      if (files == null) {
        return true;
      }
      // Run on all sub files and folders and delete them
      for (int i = 0; i < files.length; i++) {
        if (files[i].isDirectory()) {
          deleteDirectoryImpl(files[i].getAbsolutePath());
        } else {
          files[i].delete();
        }
      }
    }
    return directory.delete();
  }

  /**
   * Get all files under the directory
   * 
   * @param directory
   * @param out
   * @return
   */
  private void getDirectoryFilesImpl(File directory, List<File> out) {
    if (directory.exists()) {
      File[] files = directory.listFiles();
      if (files == null) {
        return;
      } else {
        for (int i = 0; i < files.length; i++) {
          if (files[i].isDirectory()) {
            getDirectoryFilesImpl(files[i], out);
          } else {
            out.add(files[i]);
          }
        }
      }
    }
  }

  private void closeQuietly(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
            }
        }
    }
}




Java Source Code List

com.sromku.simple.storage.AbstractDiskStorage.java
com.sromku.simple.storage.ExternalStorage.java
com.sromku.simple.storage.InternalStorage.java
com.sromku.simple.storage.SimpleStorageConfiguration.java
com.sromku.simple.storage.SimpleStorage.java
com.sromku.simple.storage.Storable.java
com.sromku.simple.storage.StorageException.java
com.sromku.simple.storage.Storage.java
com.sromku.simple.storage.helpers.ImmutablePair.java
com.sromku.simple.storage.helpers.OrderType.java
com.sromku.simple.storage.helpers.SizeUnit.java
com.sromku.simple.storage.security.CipherAlgorithmType.java
com.sromku.simple.storage.security.CipherModeType.java
com.sromku.simple.storage.security.CipherPaddingType.java
com.sromku.simple.storage.security.CipherTransformationType.java
com.sromku.simple.storage.security.SecurityUtil.java