FileHandle.java :  » Game » libgdx » com » badlogic » gdx » files » Android Open Source

Android Open Source » Game » libgdx 
libgdx » com » badlogic » gdx » files » FileHandle.java
/*
 * Copyright 2010 Mario Zechner (contact@badlogicgames.com), Nathan Sweet (admin@esotericsoftware.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package com.badlogic.gdx.files;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;

import com.badlogic.gdx.Files;
import com.badlogic.gdx.Files.FileType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.GdxRuntimeException;

/**
 * Represents a file or directory on the filesystem, classpath, Android SD card, or Android assets directory. FileHandles are
 * created via a {@link Files} instance.
 * @author mzechner
 * @author Nathan Sweet
 */
public abstract class FileHandle {
  protected File file;
  protected FileType type;

  protected FileHandle () {
  }

  protected FileHandle (String fileName, FileType type) {
    this.type = type;
    file = new File(fileName);
  }

  protected FileHandle (File file, FileType type) {
    this.file = file;
    this.type = type;
  }

  public String path () {
    return file.getPath();
  }

  public String name () {
    return file.getName();
  }

  public String extension () {
    String name = file.getName();
    int dotIndex = name.lastIndexOf('.');
    if (dotIndex == -1) return "";
    return name.substring(dotIndex + 1);
  }

  public String nameWithoutExtension () {
    String name = file.getName();
    int dotIndex = name.lastIndexOf('.');
    if (dotIndex == -1) return name;
    return name.substring(0, dotIndex);
  }

  public FileType type () {
    return type;
  }

  private File file () {
    if (type == FileType.External) return new File(Gdx.files.getExternalStoragePath(), file.getPath());
    return file;
  }

  /**
   * Returns a stream for reading this file.
   * @throw GdxRuntimeException if the file handle represents a directory, doesn't exist, or could not be read.
   */
  public InputStream read () {
    if (type == FileType.Classpath || (type == FileType.Internal && !file.exists())) {
      InputStream input = FileHandle.class.getResourceAsStream("/" + file.getPath().replace('\\', '/'));
      if (input == null) throw new GdxRuntimeException("File not found: " + file + " (" + type + ")");
      return input;
    }
    try {
      return new FileInputStream(file());
    } catch (FileNotFoundException ex) {
      if (file().isDirectory())
        throw new GdxRuntimeException("Cannot open a stream to a directory: " + file + " (" + type + ")", ex);
      throw new GdxRuntimeException("Error reading file: " + file + " (" + type + ")", ex);
    }
  }

  /**
   * Reads the entire file into a string using the platform's default charset.
   * @throw GdxRuntimeException if the file handle represents a directory, doesn't exist, or could not be read.
   */
  public String readString () {
    return readString(null);
  }

  /**
   * Reads the entire file into a string using the specified charset.
   * @throw GdxRuntimeException if the file handle represents a directory, doesn't exist, or could not be read.
   */
  public String readString (String charset) {
    StringBuilder output = new StringBuilder(512);
    InputStreamReader reader = null;
    try {
      if (charset == null)
        reader = new InputStreamReader(read());
      else
        reader = new InputStreamReader(read(), charset);
      char[] buffer = new char[256];
      while (true) {
        int length = reader.read(buffer);
        if (length == -1) break;
        output.append(buffer, 0, length);
      }
    } catch (IOException ex) {
      throw new GdxRuntimeException("Error reading layout file: " + this, ex);
    } finally {
      try {
        if (reader != null) reader.close();
      } catch (IOException ignored) {
      }
    }
    return output.toString();
  }

  /**
   * Returns a stream for writing to this file.
   * @param append If false, this file will be overwritten if it exists, otherwise it will be appended.
   * @throw GdxRuntimeException if this file handle represents a directory, if it is a {@link FileType#Classpath} or
   *        {@link FileType#Internal} file, or if it could not be written.
   */
  public OutputStream write (boolean append) {
    if (type == FileType.Classpath) throw new GdxRuntimeException("Cannot write to a classpath file: " + file);
    if (type == FileType.Internal) throw new GdxRuntimeException("Cannot write to an internal file: " + file);
    try {
      return new FileOutputStream(file(), append);
    } catch (FileNotFoundException ex) {
      if (file().isDirectory())
        throw new GdxRuntimeException("Cannot open a stream to a directory: " + file + " (" + type + ")", ex);
      throw new GdxRuntimeException("Error writing file: " + file + " (" + type + ")", ex);
    }
  }

  /**
   * Returns the paths to the children of this directory. Returns an empty list if this file handle represents a file and not a
   * directory. On the desktop, an internal handle to a directory on the classpath will return a zero length array.
   * @throw GdxRuntimeException if this file is an {@link FileType#Classpath} file.
   */
  public FileHandle[] list () {
    if (type == FileType.Classpath) throw new GdxRuntimeException("Cannot list a classpath directory: " + file);
    String[] relativePaths = file().list();
    if (relativePaths == null) return new FileHandle[0];
    FileHandle[] handles = new FileHandle[relativePaths.length];
    for (int i = 0, n = relativePaths.length; i < n; i++)
      handles[i] = child(relativePaths[i]);
    return handles;
  }

  /**
   * Returns true if this file is a directory. Always returns false for classpath files. On Android, an internal handle to an
   * empty directory will return false. On the desktop, an internal handle to a directory on the classpath will return false.
   */
  public boolean isDirectory () {
    if (type == FileType.Classpath) return false;
    return file().isDirectory();

  }

  /**
   * Returns a handle to the child with the specified name.
   * @throw GdxRuntimeException if this file handle is a {@link FileType#Classpath} or {@link FileType#Internal} and the child
   *        doesn't exist.
   */
  abstract public FileHandle child (String name);

  abstract public FileHandle parent ();

  /**
   * @throw GdxRuntimeException if this file handle is a {@link FileType#Classpath} or {@link FileType#Internal} file.
   */
  public void mkdirs () {
    if (type == FileType.Classpath) throw new GdxRuntimeException("Cannot mkdirs with a classpath file: " + file);
    if (type == FileType.Internal) throw new GdxRuntimeException("Cannot mkdirs with an internal file: " + file);
    file().mkdirs();
  }

  /**
   * Returns true if the file exists. On Android, a classpath handle to a directory will always return false.
   */
  public boolean exists () {
    switch (type) {
    case Internal:
      if (file.exists()) return true;
      // Fall through.
    case Classpath:
      return FileHandle.class.getResourceAsStream("/" + file.getPath().replace('\\', '/')) != null;
    }
    return file().exists();
  }

  /**
   * Deletes this file or empty directory and returns success. Will not delete a directory that has children.
   * @throw GdxRuntimeException if this file handle is a {@link FileType#Classpath} or {@link FileType#Internal} file.
   */
  public boolean delete () {
    if (type == FileType.Classpath) throw new GdxRuntimeException("Cannot delete a classpath file: " + file);
    if (type == FileType.Internal) throw new GdxRuntimeException("Cannot delete an internal file: " + file);
    return file().delete();
  }

  /**
   * Deletes this file or directory and all children, recursively.
   * @throw GdxRuntimeException if this file handle is a {@link FileType#Classpath} or {@link FileType#Internal} file.
   */
  public boolean deleteDirectory () {
    if (type == FileType.Classpath) throw new GdxRuntimeException("Cannot delete a classpath file: " + file);
    if (type == FileType.Internal) throw new GdxRuntimeException("Cannot delete an internal file: " + file);
    return deleteDirectory(file());
  }

  /**
   * Copies this file to the specified file, overwriting the file if it already exists.
   * @throw GdxRuntimeException if the destination file handle is a {@link FileType#Classpath} or {@link FileType#Internal} file.
   */
  public void copyTo (FileHandle dest) {
    InputStream input = null;
    OutputStream output = null;
    try {
      input = read();
      output = dest.write(false);
      byte[] buffer = new byte[4096];
      while (true) {
        int length = input.read(buffer);
        if (length == -1) break;
        output.write(buffer, 0, length);
      }
    } catch (Exception ex) {
      throw new GdxRuntimeException("Error copying source file: " + file + " (" + type + ")\n" //
        + "To destination: " + dest.file + " (" + dest.type + ")", ex);
    } finally {
      try {
        if (input != null) input.close();
      } catch (Exception ignored) {
      }
      try {
        if (output != null) output.close();
      } catch (Exception ignored) {
      }
    }
  }

  /**
   * Moves this file to the specified file, overwriting the file if it already exists.
   * @throw GdxRuntimeException if the source or destination file handle is a {@link FileType#Classpath} or
   *        {@link FileType#Internal} file.
   */
  public void moveTo (FileHandle dest) {
    if (type == FileType.Classpath) throw new GdxRuntimeException("Cannot move a classpath file: " + file);
    if (type == FileType.Internal) throw new GdxRuntimeException("Cannot move an internal file: " + file);
    copyTo(dest);
    delete();
  }

  /**
   * Returns the length in bytes of this file, or 0 if this file is a directory or does not exist.
   */
  public long length () {
    if (type == FileType.Classpath || (type == FileType.Internal && !file.exists())) {
      try {
        InputStream input = read();
        long length = input.available();
        try {
          input.close();
        } catch (Exception ignored) {
        }
        return length;
      } catch (Exception ignored) {
      }
      return 0;
    }
    return file().length();
  }

  public String toString () {
    return file.getPath();
  }

  static private boolean deleteDirectory (File file) {
    if (file.exists()) {
      File[] files = file.listFiles();
      if (files != null) {
        for (int i = 0, n = files.length; i < n; i++) {
          if (files[i].isDirectory())
            deleteDirectory(files[i]);
          else
            files[i].delete();
        }
      }
    }
    return file.delete();
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.