android load inputstream assets objectinputstream

android - Cargar archivos de más de 1M de la carpeta de activos



load inputstream (11)

Me estoy volviendo loco, creé un objeto de archivo, por lo que se puede leer con ObjectInputStream y coloqué la carpeta de activos. El método funciona con un archivo más pequeño que 1M y da error con archivos más grandes. Leí que es un límite de la plataforma Android, pero también sé que se puede evitar "fácilmente". Aquellos que han descargado el juego Reging Thunder, por ejemplo, pueden ver fácilmente que en su carpeta de activos hay un archivo de 18.9M de ancho. Este es mi código para leer 1 objeto de un ObjecInputStream

File f = File.createTempFile("mytempfile", "dat"); FileOutputStream fos = new FileOutputStream(f); InputStream is = mc.getAssets().open(path,3); ObjectInputStream ois=new ObjectInputStream(is); byte[] data = (byte[]) ois.readObject(); fos.write(data); fos.flush(); fos.close(); ois.close(); is.close();

ahora tengo un archivo descomprimido y puedo usarlo sin preocuparme por el error "Este archivo no se puede abrir como un descriptor de archivo, probablemente esté comprimido"

Esta función funciona bien con archivos menores a 1M, con archivos más grandes devuelve una java.io.IOException en la línea "ObjectInputStream ois = new ObjectInputStream (is);"

¿¿por qué??


Como Seva sugirió que puedes dividir tu archivo en fragmentos. Usé esto para dividir mi archivo de 4MB

public static void main(String[] args) throws Exception { String base = "tracks"; String ext = ".dat"; int split = 1024 * 1024; byte[] buf = new byte[1024]; int chunkNo = 1; File inFile = new File(base + ext); FileInputStream fis = new FileInputStream(inFile); while (true) { FileOutputStream fos = new FileOutputStream(new File(base + chunkNo + ext)); for (int i = 0; i < split / buf.length; i++) { int read = fis.read(buf); fos.write(buf, 0, read); if (read < buf.length) { fis.close(); fos.close(); return; } } fos.close(); chunkNo++; } }

Si no necesita combinar los archivos en un solo archivo en el dispositivo nuevamente, simplemente use este InputStream, que los combina en uno sobre la marcha.

import java.io.IOException; import java.io.InputStream; import android.content.res.AssetManager; public class SplitFileInputStream extends InputStream { private String baseName; private String ext; private AssetManager am; private int numberOfChunks; private int currentChunk = 1; private InputStream currentIs = null; public SplitFileInputStream(String baseName, String ext, int numberOfChunks, AssetManager am) throws IOException { this.baseName = baseName; this.am = am; this.numberOfChunks = numberOfChunks; this.ext = ext; currentIs = am.open(baseName + currentChunk + ext, AssetManager.ACCESS_STREAMING); } @Override public int read() throws IOException { int read = currentIs.read(); if (read == -1 && currentChunk < numberOfChunks) { currentIs.close(); currentIs = am.open(baseName + ++currentChunk + ext, AssetManager.ACCESS_STREAMING); return read(); } return read; } @Override public int available() throws IOException { return currentIs.available(); } @Override public void close() throws IOException { currentIs.close(); } @Override public void mark(int readlimit) { throw new UnsupportedOperationException(); } @Override public boolean markSupported() { return false; } @Override public int read(byte[] b, int offset, int length) throws IOException { int read = currentIs.read(b, offset, length); if (read < length && currentChunk < numberOfChunks) { currentIs.close(); currentIs = am.open(baseName + ++currentChunk + ext, AssetManager.ACCESS_STREAMING); read += read(b, offset + read, length - read); } return read; } @Override public int read(byte[] b) throws IOException { return read(b, 0, b.length); } @Override public synchronized void reset() throws IOException { if (currentChunk == 1) { currentIs.reset(); } else { currentIs.close(); currentIs = am.open(baseName + currentChunk + ext, AssetManager.ACCESS_STREAMING); currentChunk = 1; } } @Override public long skip(long n) throws IOException { long skipped = currentIs.skip(n); if (skipped < n && currentChunk < numberOfChunks) { currentIs.close(); currentIs = am.open(baseName + ++currentChunk + ext, AssetManager.ACCESS_STREAMING); skipped += skip(n - skipped); } return skipped; } }

Uso:
ObjectInputStream ois = new ObjectInputStream(new SplitFileInputStream("mytempfile", ".dat", 4, getAssets()));


En lugar de la carpeta de activos, he puesto mis archivos grandes en la carpeta sin formato. Esto funciona para mi.


Encontré otra solución, tal vez estás interesado en ella.

En la raíz de sus fuentes, donde tiene el archivo build.xml , puede sobrescribir el objetivo custom_rules.xml -package-resources en el archivo custom_rules.xml , que se usa para agregar / modificar objetivos en la hormiga sin romper nada en la aplicación estándar de Android. sistema de construcción.

Solo crea un archivo con este contenido:

<?xml version="1.0" encoding="UTF-8"?> <project name="yourAppHere" default="help"> <target name="-package-resources" depends="-crunch"> <!-- only package resources if *not* a library project --> <do-only-if-not-library elseText="Library project: do not package resources..." > <aapt executable="${aapt}" command="package" versioncode="${version.code}" versionname="${version.name}" debug="${build.is.packaging.debug}" manifest="${out.manifest.abs.file}" assets="${asset.absolute.dir}" androidjar="${project.target.android.jar}" apkfolder="${out.absolute.dir}" nocrunch="${build.packaging.nocrunch}" resourcefilename="${resource.package.file.name}" resourcefilter="${aapt.resource.filter}" libraryResFolderPathRefid="project.library.res.folder.path" libraryPackagesRefid="project.library.packages" libraryRFileRefid="project.library.bin.r.file.path" previousBuildType="${build.last.target}" buildType="${build.target}" ignoreAssets="${aapt.ignore.assets}"> <res path="${out.res.absolute.dir}" /> <res path="${resource.absolute.dir}" /> <nocompress /> <!-- forces no compression on any files in assets or res/raw --> <!-- <nocompress extension="xml" /> forces no compression on specific file extensions in assets and res/raw --> </aapt> </do-only-if-not-library> </target> </project>


Enfrentado con el mismo problema. Corté mi archivo de 4MB en trozos de 1 MB, y en la primera ejecución uní los trozos en una carpeta de datos en el teléfono. Como una ventaja adicional, el APK está comprimido correctamente. Los archivos de fragmentos se llaman 1.db, 2.db, etc. El código es así:

File Path = Ctxt.getDir("Data", 0); File DBFile = new File(Path, "database.db"); if(!DBFile.exists() || DatabaseNeedsUpgrade) //Need to copy... CopyDatabase(Ctxt, DBFile); static private void CopyDatabase(Context Ctxt, File DBFile) throws IOException { AssetManager assets = Ctxt.getAssets(); OutputStream outstream = new FileOutputStream(DBFile); DBFile.createNewFile(); byte []b = new byte[1024]; int i, r; String []assetfiles = assets.list(""); Arrays.sort(assetfiles); for(i=1;i<10;i++) //I have definitely less than 10 files; you might have more { String partname = String.format("%d.db", i); if(Arrays.binarySearch(assetfiles, partname) < 0) //No such file in assets - time to quit the loop break; InputStream instream = assets.open(partname); while((r = instream.read(b)) != -1) outstream.write(b, 0, r); instream.close(); } outstream.close(); }


La limitación está en los activos comprimidos. Si el activo no está comprimido, el sistema puede mapear la memoria de los datos del archivo y usar el sistema de paginación de la memoria virtual de Linux para extraer o descartar fragmentos de 4K, según corresponda. (La herramienta "zipalign" asegura que los activos no comprimidos estén alineados con las palabras en el archivo, lo que significa que también estarán alineados en la memoria cuando se mapeen directamente).

Si el activo está comprimido, el sistema tiene que descomprimir todo en la memoria. Si tienes un activo de 20MB, eso significa que tu aplicación está atada a 20MB de memoria física.

Lo ideal es que el sistema emplee algún tipo de compresión en ventanas, por lo que solo deben estar presentes las partes, pero eso requiere cierta sofisticación en la API de activos y un esquema de compresión que funciona bien con acceso aleatorio. En este momento, APK == Zip con compresión "desinflar", por lo que no es práctico.

Puede mantener sus activos sin comprimir dándoles un sufijo de un tipo de archivo que no se comprima (por ejemplo, ".png" o ".mp3"). También puede agregarlos manualmente durante el proceso de compilación con "zip -0" en lugar de tenerlos empaquetados por aapt. Esto probablemente aumentará el tamaño de su APK.


Sé que esta es una vieja pregunta, pero pensé en una buena solución. ¿Por qué no almacenar el archivo ya precomprimido en la carpeta de activos? Entonces, dado que ya es un archivo comprimido y, por lo tanto, comprimido, no será necesario volver a comprimirlo. Entonces, si quisieras que el archivo se comprimiera para disminuir el tamaño de tu apk, pero no quieres lidiar con la división de archivos, creo que es más fácil.

Cuando necesite leer ese archivo del dispositivo, simplemente ajuste la ruta de entrada en zipinputstream http://developer.android.com/reference/java/util/zip/ZipInputStream.html


Usar GZIP sería otro método. solo necesita envolver InputStream dentro de GZIPInputStream .

Lo usé para una base de datos cuyo tamaño de aproximadamente 3.0 MB y el archivo de compresión de salida era de aproximadamente 600 KB.

  • Para copiar DB en primera ejecución, compré gzip mi archivo .db fuente usando la herramienta GZIP .
  • Luego se renombró a .jpg para evitar más compresión (estos procesos se realizan antes de compilar APK FILE).
  • Luego, para leer el archivo comprimido GZIP de assetss

y copiarlo:

private void copydatabase() throws IOException { // Open your local db as the input stream InputStream myinput = mContext.getAssets().open(DB_NAME_ASSET); BufferedInputStream buffStream = new BufferedInputStream(myinput); GZIPInputStream zis = new GZIPInputStream(buffStream); // Path to the just created empty db String outfilename = DB_PATH + DB_NAME; // Open the empty db as the output stream OutputStream myoutput = new FileOutputStream(outfilename); // transfer byte to inputfile to outputfile byte[] buffer = new byte[1024]; int length; while ((length = zis.read(buffer)) > 0) { myoutput.write(buffer, 0, length); } // Close the streams myoutput.flush(); myoutput.close(); zis.close(); buffStream.close(); myinput.close(); }


Utilizo NetBeans para compilar el paquete y no encontré cómo cambiar la configuración de AAPT. No he probado el png, pero los mp3 están comprimidos. Puedo compilar el paquete y luego ingresar a la carpeta de activos con el parámetro -0? ¿Cuál sería el comando correcto para usar?


agregar extensión de archivo es mp3.I uso la carpeta mydb.mp3in assets y copio .this se ejecuta sin error.show check it.



une methode pas propre consiste en un cambio de extensión du fichier ttf a mp3