web-dev-qa-db-fra.com

Charger des fichiers plus gros que 1M à partir du dossier assets

Je deviens fou, j'ai créé un objet fichier, qui peut donc être lu avec ObjectInputStream et j'ai placé le dossier assets . La méthode fonctionne avec un fichier inférieur à 1M et génère une erreur avec des fichiers plus volumineux . J'ai lu que c'était une limite de la plate-forme Android, mais je sais aussi qu'on peut "facilement" l'éviter . Ceux qui ont téléchargé le jeu Reging Thunder, par exemple, peuvent facilement voir que leur dossier d'actifs est un fichier 18,9M large . Ceci est mon code pour lire 1 objet 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 me soucier 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 les fichiers plus petits que 1M, les fichiers plus volumineux retournant une exception Java.io.IOException en ligne "ObjectInputStream ois = new ObjectInputStream (is);"

pourquoi??

36
Syco

Face au même problème. J'ai découpé mon fichier de 4 Mo en morceaux de 1 Mo et, lors de la première exécution, j'ai joint les morceaux dans un dossier de données sur le téléphone. En prime, l'APK est correctement compressé. Les fichiers de morceaux s'appellent 1.db, 2.db, etc. Le code va comme ceci:

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

La limitation concerne les actifs compressés. Si la ressource est décompressée, le système peut mapper en mémoire les données du fichier et utiliser le système de pagination à mémoire virtuelle Linux pour extraire ou ignorer des fragments 4K selon le cas. (L'outil "zipalign" garantit que les éléments non compressés sont alignés sur Word dans le fichier, ce qui signifie qu'ils seront également alignés en mémoire lorsqu'ils seront directement mappés.)

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

Idéalement, le système devrait utiliser une sorte de compression fenêtrée, de sorte que seules certaines parties doivent être présentes, mais cela nécessite une certaine fantaisie dans l'API d'actif et un schéma de compression qui fonctionne bien avec un accès aléatoire. En ce moment, APK == Zip avec une compression "deflate", ce n’est donc pas pratique.

Vous pouvez conserver vos ressources non compressées en leur attribuant un suffixe d'un type de fichier non compressé (par exemple, ".png" ou ".mp3"). Vous pouvez également pouvoir les ajouter manuellement pendant le processus de construction avec "Zip -0" au lieu de les regrouper avec aapt. Cela augmentera probablement la taille de votre APK.

32
fadden

Changer l'extension de fichier en .mp3

7
yassine

J'ai trouvé une autre solution, peut-être que ça vous intéresse.

À la racine de vos sources, où vous avez le fichier build.xml, vous pouvez écraser la cible -package-resources dans le fichier custom_rules.xml, qui est utilisée pour ajouter/modifier des cibles dans ant sans rien casser dans le système de génération d'applications Android standard.

Il suffit de créer 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>
2
Ottavio Campana

Je sais que c’est une vieille question, mais j’ai pensé à une bonne solution . Pourquoi ne pas stocker le fichier déjà pré-compressé dans le dossier des actifs . Ensuite, comme il s’agit déjà d’un fichier Zip, il ne sera donc pas compressé. besoin d'être compressé à nouveau. Donc, si vous vouliez que le fichier soit compressé pour réduire la taille de votre apk mais que vous ne vouliez pas vous séparer, je pense que c'est plus facile.

Lorsque vous avez besoin de lire ce fichier hors du périphérique, enveloppez simplement le flux d'entrée dans un fichier zipinputstream http://developer.Android.com/reference/Java/util/Zip/ZipInputStream.html

2
Matt Wolfe

définir la base de données en plusieurs parties avec un programme, par exemple "Win Hex", vous pouvez télécharger à partir de Link

et continuer Charger des fichiers plus gros que 1M à partir du dossier assets

0
Ehsan Jelodar

l’extension d’ajout de fichier est mp3.J’utilise le dossier d’actifs mydb.mp3in et je copie. Cette exécution s’effectue sans erreur.

0
santosh Kundkar

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

0
the100rabh

Utiliser GZIP serait une autre méthode. vous devez seulement envelopper InputStream dans GZIPInputStream

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

  • Pour copier une base de données en premier, j'ai compressé mon fichier source .db avec GZIP Tool
  • Puis renommé en .jpg afin d'éviter davantage de compression (Ces processus sont effectués avant la compilation de APK FILE). 
  • Ensuite, pour lire le fichier GZIP compressé à partir des ressources 

et en le copiant:

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