wake-up-neo.com

Laden Sie Dateien, die größer als 1 MB sind, aus dem Ordner Assets

Ich werde verrückt, ich habe ein Dateiobjekt erstellt, damit es mit ObjectInputStream gelesen werden kann, und ich habe den Ordner mit den Assets platziert .. Die Methode arbeitet mit einer Datei, die kleiner als 1 MB ist, und gibt bei größeren Dateien einen Fehler aus. Ich habe gelesen, dass dies eine Beschränkung der Android-Plattform ist, aber ich weiß auch, dass "leicht" vermieden werden kann . Wer beispielsweise das Spiel "Reging Thunder" heruntergeladen hat, kann leicht erkennen, dass sich in seinem Assets-Ordner eine Datei mit 18,9 MB befindet large . Dies ist mein Code zum Lesen eines Objekts aus einem 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();

ich habe jetzt eine unkomprimierte Datei und kann sie verwenden, ohne sich um den Fehler kümmern zu müssen. "Diese Datei kann nicht als Dateideskriptor geöffnet werden. Sie ist wahrscheinlich komprimiert."

Diese Funktion eignet sich gut für Dateien, die kleiner als 1 MB sind. Größere Dateien geben in der Zeile eine Java.io.IOException zurück. "ObjectInputStream ois = new ObjectInputStream (is);"

warum??

36
Syco

Konfrontiert mit demselben Problem. Ich habe meine 4-MB-Datei in 1-MB-Blöcke aufgeteilt, und beim ersten Lauf füge ich die Blöcke in einem Datenordner auf dem Telefon zusammen. Als zusätzlicher Bonus wird die APK richtig komprimiert. Die Chunk-Dateien heißen 1.db, 2.db usw. Der Code lautet folgendermaßen:

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

Die Einschränkung gilt für komprimierte Assets. Wenn das Asset unkomprimiert ist, kann das System die Dateidaten im Speicher zuordnen und das virtuelle Paging-System für virtuellen Arbeitsspeicher verwenden, um 4K-Blöcke nach Bedarf einzuziehen oder zu verwerfen. (Das Tool "zipalign" stellt sicher, dass nicht komprimierte Assets in der Datei Word-ausgerichtet sind. Dies bedeutet, dass sie auch direkt im Speicher ausgerichtet werden, wenn sie direkt zugeordnet werden.)

Wenn das Asset komprimiert ist, muss das System die gesamte Sache in den Speicher dekomprimieren. Wenn Sie über ein 20-MB-Asset verfügen, bedeutet dies, dass 20 MB physischer Speicher von Ihrer Anwendung gebunden sind.

Im Idealfall würde das System eine Art Fensterkomprimierung verwenden, so dass nur Teile vorhanden sein müssen. Dies erfordert jedoch etwas Fantasie in der Asset-API und ein Komprimierungsschema, das bei Direktzugriff gut funktioniert. Im Moment ist APK == Zip mit "deflate" Komprimierung, das ist also nicht praktikabel.

Sie können Ihre Assets unkomprimiert halten, indem Sie ihnen ein Suffix eines Dateityps geben, der nicht komprimiert wird (z. B. ".png" oder ".mp3"). Sie können sie möglicherweise auch während des Erstellungsprozesses manuell mit "Zip -0" hinzufügen, anstatt sie von aapt gebündelt zu haben. Dies erhöht wahrscheinlich die Größe Ihres APK.

32
fadden

Wie Seva vorgeschlagen hat, können Sie Ihre Datei in Stücke aufteilen. Ich habe das benutzt, um meine 4MB Datei aufzuteilen

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

Wenn Sie die Dateien auf dem Gerät nicht erneut zu einer einzigen Datei kombinieren müssen, verwenden Sie einfach diesen InputStream, der sie im Handumdrehen zu einer einzigen Datei kombiniert.

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

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

9
Oliver

Ändern Sie die Dateierweiterung in .mp3

7
yassine

Ich habe eine andere Lösung gefunden, vielleicht interessieren Sie sich dafür.

Im Stammverzeichnis Ihrer Quellen, wo Sie über die Datei build.xml verfügen, können Sie das Ziel -package-resources in der Datei custom_rules.xml überschreiben, die zum Hinzufügen/Ändern von Zielen in ant verwendet wird, ohne dass das Standardsystem der Android-App-Erstellung beschädigt wird.

Erstellen Sie einfach eine Datei mit diesem Inhalt:

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

Ich weiß, dass dies eine alte Frage ist, aber ich habe an eine gute Lösung gedacht. Warum speichern Sie die Datei nicht bereits im ZIP-Ordner im Asset-Ordner .. Dann wird sie nicht komprimiert, da es sich bereits um eine ZIP-Datei handelt müssen erneut komprimiert werden. Wenn Sie möchten, dass die Datei komprimiert wird, um die Größe Ihrer Apk zu verringern, Sie sich jedoch nicht mit dem Aufteilen von Dateien beschäftigen möchten, ist dies meiner Meinung nach einfacher.

Wenn Sie diese Datei vom Gerät lesen müssen, wickeln Sie den Eingabestrom einfach in einen zipinputstream ein http://developer.Android.com/reference/Java/util/Zip/ZipInputStream.html

2
Matt Wolfe

setzen Sie die Datenbank mit einem Programm auf mehrere Teile, z. B. "Win Hex". Sie können sie von Link herunterladen.

und fortsetzen Laden Sie Dateien, die größer als 1 MB sind, aus dem Ordner Assets

0
Ehsan Jelodar

dateierweiterung hinzufügen ist mp3.Ich benutze mydb.mp3in Assets Ordner und kopiere .dies läuft ohne Fehler.

0
santosh Kundkar

Anstelle des Assets-Ordners habe ich meine großen Dateien im Raw-Ordner abgelegt. Für mich geht das. 

0
the100rabh

Die Verwendung von GZIP wäre eine andere Methode. Sie müssen nur InputStream in GZIPInputStream einschließen. 

Ich habe dies für eine Datenbank mit einer Größe von etwa 3,0 MB und einer Ausgabekomprimierungsdatei von etwa 600 KB verwendet.

  • Für das Kopieren von DBs im ersten Lauf habe ich meine .db-Quelldatei mit GZIP Tool gepackt. 
  • Dann umbenannt in .jpg, um weitere Komprimierung zu vermeiden. (Diese Vorgänge werden vor dem Kompilieren von APK FILE ausgeführt). 
  • Dann zum Lesen der komprimierten GZIP-Datei aus Assetss 

und kopiere es:

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