Charger des fichiers de plus de 1 M à partir du dossier d'actifs

Je devenais fou, j'ai créé un objet de fichier, donc il peut être lu avec ObjectInputStream, et j'ai placé le dossier d'actifs. La méthode fonctionne avec un fichier inférieur à 1M et donne une erreur avec des fichiers plus importants. J'ai lu que c'est une limite de la plate-forme Android, mais je sais aussi que cela peut être «facilement» évité. Ceux qui ont téléchargé le jeu Reging Thunder, par exemple, peuvent facilement voir que dans leur dossier d'actifs se trouve un fichier de 18,9M de largeur. C'est mon code pour l'objet lue 1 d'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(); 

Maintenant, j'ai un fichier non compressé et je peux l'utiliser sans m'inquiéter de l'erreur "Ce fichier ne peut pas être ouvert en tant que descripteur de fichier, il est probablement compressé"

Cette fonction fonctionne bien avec des fichiers de moins de 1 M, avec des fichiers plus gros renvoient une java.io.IOException en ligne "ObjectInputStream ois = new ObjectInputStream (is);"

Pourquoi??

11 Solutions collect form web for “Charger des fichiers de plus de 1 M à partir du dossier d'actifs”

Face au même problème. J'ai coupé mon fichier de 4 Mo en morceaux de 1 Mo et, lors de la première exécution, je rejoins les morceaux dans un dossier de données sur le téléphone. En complément, l'APK est correctement compressé. Les fichiers chunk sont appelés 1.db, 2.db, etc. Le code est ainsi:

 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 limitation concerne les actifs compressés. Si l'élément n'est pas compressé, le système peut mémoriser les données du fichier et utiliser le système de pagination de la mémoire virtuelle Linux pour retirer ou jeter les blocs 4K, le cas échéant. (L'outil "zipalign" garantit que les actifs non compressés sont alignés dans le fichier, ce qui signifie qu'ils seront également alignés dans la mémoire lorsqu'ils seront directement mappés.)

Si l'actif est compressé, le système doit décompresser l'intégralité de la mémoire. Si vous avez un atout de 20 Mo, cela signifie que 20 Mo de mémoire physique est lié par votre application.

Idéalement, le système utiliserait une sorte de compression par fenêtrage, de sorte que seules les pièces doivent être présentes, mais cela nécessite une certaine fiabilité dans l'API des actifs et un schéma de compression qui fonctionne bien avec l'accès aléatoire. À l'heure actuelle APK == Zip avec la compression "dégonfler", ce qui n'est pas pratique.

Vous pouvez conserver vos actifs non compressés en leur donnant un suffixe d'un type de fichier qui ne se comprime pas (p. Ex. ".png" ou ".mp3"). Vous pouvez également les ajouter manuellement pendant le processus de compilation avec "zip -0" au lieu de les faire regrouper par aapt. Cela augmentera probablement la taille de votre APK.

Comme Seva a suggéré, vous pouvez diviser votre fichier en morceaux. J'ai utilisé cela pour diviser mon fichier de 4 Mo

 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 vous n'avez pas besoin de combiner les fichiers dans un seul fichier sur le périphérique, utilisez simplement InputStream, qui les combine en un seul.

 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; } } 

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

Une methode pas propre consiste en un changeur d'extention du fichier ttf a mp3

J'ai trouvé une autre solution, peut-être que vous êtes intéressé.

Dans la racine de vos sources, où vous avez le build.xml , vous pouvez remplacer la cible custom_rules.xml -package-resources dans le fichier custom_rules.xml , qui est utilisé pour ajouter / modifier des cibles en fourmi sans casser quoi que ce soit dans l'application Android standard Système de construction.

Créez simplement un fichier avec ce contenu:

 <?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> 

Je sais que c'est une vieille question, mais j'ai pensé à une bonne solution. Pourquoi ne pas stocker le fichier déjà pré-zip dans le dossier de l'actif. Ensuite, puisqu'il s'agit déjà d'un fichier zip et donc compressé, il ne sera pas nécessaire de le compresser à nouveau. Donc, si vous vouliez que le fichier soit compressé pour diminuer la taille de votre apk, mais que vous ne voulez pas répartir les fichiers, je pense qu'il est plus facile.

Lorsque vous devez lire ce fichier hors de l'appareil, il suffit d'envelopper les entrées dans un zipinputstream http://developer.android.com/reference/java/util/zip/ZipInputStream.html

Ajouter une extension de fichier est mp3.J'utilise mydb.mp3in dossier d'actifs et copier. Ceci s'exécute sans erreur. Regardez-le.

L'utilisation de GZIP serait une autre méthode. Il vous suffit d'envelopper InputStream à l' intérieur de GZIPInputStream .

Je l'ai utilisé pour une base de données dont la taille d'environ 3,0 Mo et le fichier de compression de sortie était d'environ 600 Ko.

  • Pour copier DB dans la première exécution, j'ai gzipped mon fichier source .db à l'aide de l' outil GZIP .
  • Ensuite, il a été renommé à .jpg afin d'éviter une compression supplémentaire (ces processus sont effectués avant de compiler APK FILE).
  • Ensuite, pour lire le fichier GZIP compressé à partir des actifs

Et le copier:

 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(); } 

Définissez la base de données sur une partie multiple avec un programme, par exemple "Win Hex", vous pouvez télécharger à partir de Link

Et continuer Charger des fichiers de plus de 1 M à partir du dossier d'actifs

Au lieu du dossier d'actifs, j'ai mis mes gros fichiers dans le dossier brut. Ça marche pour moi.

J'utilise NetBeans pour créer le package et je n'ai pas trouvé comment modifier les paramètres d'AAPT. Je n'ai pas essayé le png, mais les mp3 sont compressés. Je peux compiler le paquet puis entrer le dossier d'actifs avec le paramètre -0? Quelle serait la bonne commande à utiliser?

coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.