2011-12-06 8 views
13

Hej,determinar wheteher entrada activo androide es un archivo o directorio

tengo algunos datos enviados a cabo con la aplicación que se copian en el almacenamiento externo. Está anidado en un par de subcarpetas y me gustaría copiar toda la estructura.

Me está costando conseguir un objeto File para cualquier recurso en /assets. Pero creo que dependo de eso porque necesito algo como File.isDirectory() para determinar si tengo que comenzar a copiar o sumergirme más profundamente en el sistema.

Mi primer enfoque fue usar Assets Manager pero parece que la clase no proporciona la información que necesito. El más prometedor fue obtener un AssetFileDescriptor y bajar a un [FileDescriptor][2]. Sin embargo, ninguno de ellos parece tener un isDirectory -metodo.

Así que mi otro enfoque es sencillo: crear un objeto de archivo y ser feliz. Sin embargo, parece que estoy corriendo en este problema de falta de una ruta adecuada para instanciar el objeto de archivo. Soy consciente de file://android_asset pero no parece funcionar para el constructor file.

Mi última idea era utilizar el InputStream (que necesito para copiar de todos modos) y de alguna manera filtrar el byte por un bit significativo que indica que este recurso es un directorio. Esa es una solución bastante hacky y probablemente en el infierno de la ineficacia, pero no veo otra manera de evitar eso.

+0

También puede consultar https://stackoverflow.com/a/46827944/2179872, que hace una combinación de los dos métodos *** AssetManager.list() *** y *** AssetManager.open() *** – Cosmin

Respuesta

4

list() en AssetManager probablemente dará una matriz nula/de longitud cero/IOException si intenta obtener una lista en un archivo, pero una respuesta válida en un directorio.

Pero por lo demás debe ser file: /// android_asset (con 3 /)

+0

Voy a echar un vistazo al list-hack. sí, pero el uso de nuevo archivo (file: ///android_asset/foo.bar) no parece funcionar. Realmente no sé qué tipo de objeto recibo, pero falla para ambas pruebas: isDirectory() AND (!) IsFile(). – yoshi

+1

Ojalá pudiera votar dos veces por esta respuesta. 'String [] s = am.list (filename)' arrojará una 'IOException' en el caso de que filename sea un archivo. Me gusta mucho esta solución, ¡muchas gracias! – yoshi

+0

Sin embargo, list() es muy lento (vea la otra respuesta) –

12

que tenía el mismo problema. En algún momento me di cuenta de que list() es muy lento (50ms en cada llamada), entonces estoy usando un enfoque diferente ahora:

Tengo un generador de hormigas (eclipse) que crea un archivo de índice cada vez que mi activo- cambios de carpeta. El archivo solo contiene un nombre de archivo por línea, por lo que los directorios se enumeran implícitamente (si no están vacíos).

El Constructor:

<?xml version="1.0"?> 
<project default="createAssetIndex"> 
    <target name="createAssetIndex"> 
     <fileset id="assets.fileset" dir="assets/" includes="**" 
      excludes="asset.index" /> 
     <pathconvert pathsep="${line.separator}" property="assets" 
      refid="assets.fileset"> 
      <mapper> 
       <globmapper from="${basedir}/assets/*" to="*" 
        handledirsep="yes" /> 
      </mapper> 
     </pathconvert> 
     <echo file="assets/asset.index">${assets}</echo> 
    </target> 
</project> 

La clase que carga asset.index en una lista de cadenas, por lo que puede hacer cosas arbitraria con él, rápido:

import android.content.ContextWrapper; 

import com.google.common.collect.ImmutableList; 

import java.io.BufferedInputStream; 
import java.io.File; 
import java.io.IOException; 
import java.io.InputStream; 

import java.util.Scanner; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

/** 
* uses asset.index file (which is pregenerated) since asset-list()s take very long 
* 
*/ 
public final class AssetIndex { 

    //~ Static fields/initializers ------------------------------------------------------------------------------------- 

    private static final Logger L = LoggerFactory.getLogger(AssetIndex.class); 

    //~ Instance fields ------------------------------------------------------------------------------------------------ 

    private final ImmutableList<String> files; 

    //~ Constructors --------------------------------------------------------------------------------------------------- 

    public AssetIndex(final ContextWrapper contextWrapper) { 

     ImmutableList.Builder<String> ib = ImmutableList.builder(); 

     L.debug("creating index from assets"); 

     InputStream in = null; 
     Scanner scanner = null; 
     try { 
      in   = contextWrapper.getAssets().open("asset.index"); 
      scanner  = new Scanner(new BufferedInputStream(in)); 

      while (scanner.hasNextLine()) { 
       ib.add(scanner.nextLine()); 
      } 

      scanner.close(); 
      in.close(); 

     } catch (final IOException e) { 
      L.error(e.getMessage(), e); 
     } finally { 
      if (scanner != null) { 
       scanner.close(); 
      } 
      if (in != null) { 
       try { 
        in.close(); 
       } catch (final IOException e) { 
        L.error(e.getMessage(), e); 
       } 
      } 
     } 

     this.files = ib.build(); 
    } 

    //~ Methods -------------------------------------------------------------------------------------------------------- 

    /* returns the number of files in a directory */ 
    public int numFiles(final String dir) { 

     String directory = dir; 
     if (directory.endsWith(File.separator)) { 
      directory = directory.substring(0, directory.length() - 1); 
     } 

     int num = 0; 
     for (final String file : this.files) { 
      if (file.startsWith(directory)) { 

       String rest = file.substring(directory.length()); 
       if (rest.charAt(0) == File.separatorChar) { 
        if (rest.indexOf(File.separator, 1) == -1) { 
         num = num + 1; 
        } 
       } 
      } 
     } 

     return num; 
    } 
} 
+1

Esto es muy bueno y útil, pero necesitaba agregar 'dirsep ='/'' a pathconvert. De lo contrario, en Windoze Java dice que el separador de ruta es '\', lo que no funciona en el administrador de activos de Android – Flynny75

+1

Para aquellos que luchan con esto y usan Gradle, ver http://stackoverflow.com/questions/18569983/androidgradle-list-directories -in-un-archivo –

2

En mi caso concreto, los archivos normales tener un nombre como filename.ext, mientras que los directorios solo tienen un nombre, sin extensión, y su nombre nunca contiene el "." (punto) personaje Así un archivo normal se puede distinguir de un directorio probando su nombre de la siguiente manera:

filename.contains(".") 

Si su caso también, la misma solución debe trabajar para usted.

+0

¡Brillante! Me ahorró hasta el 80% del tiempo de carga normal. –

Cuestiones relacionadas