Załaduj pliki większe niż 1M z folderu zasoby

Szaleję, stworzyłem obiekt file, więc można go odczytać za pomocą ObjectInputStream i umieściłem folder assets. Metoda działa z plikiem mniejszym niż 1M i daje błąd przy większych plikach. Czytałem, że jest to limit Platformy Android, ale wiem też, że można "łatwo" uniknąć. Ci, którzy pobrali grę Reging Thunder, na przykład, można łatwo zobaczyć, że w ich folderze zasobów jest plik 18.9 m duży. To jest mój kod do odczytu 1 obiektu z 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();

Teraz mam nieskompresowany plik i mogę go używać bez obawy o błąd "ten plik nie może być otwarty jako deskryptor pliku; prawdopodobnie jest skompresowany"

Ta funkcja działa dobrze z plikami mniejszymi niż 1M, przy większych plikach zwraca java.io. IOException on line "ObjectInputStream ois=new ObjectInputStream (is);"

Dlaczego??
Author: Syco, 2010-05-18

11 answers

W obliczu tego samego problemu. Wyciąłem mój plik 4MB na kawałki 1 MB, a przy pierwszym uruchomieniu dołączam kawałki do folderu danych w telefonie. Jako dodatkowy bonus, APK jest odpowiednio skompresowany. Pliki chunk nazywane są 1.db, 2.db, itp. Kod wygląda tak:

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
Author: Seva Alekseyev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-08 16:05:29

Ograniczenie dotyczy aktywów skompresowanych. Jeśli zasób jest nieskompresowany, system może mapować dane plików w pamięci i używać linuksowego systemu stronicowania pamięci wirtualnej do ściągania lub odrzucania fragmentów 4K. (Narzędzie "zipalign" zapewnia, że nieskompresowane zasoby są wyrównane w słowie w pliku, co oznacza, że będą również wyrównane w pamięci, gdy zostaną bezpośrednio zmapowane.)

Jeśli zasób jest skompresowany, system musi rozpakować całość do pamięci. Jeśli masz 20MB zasobów, to oznacza, że 20MB pamięci fizycznej jest związane przez aplikację.

Najlepiej byłoby, gdyby system zastosował jakiś rodzaj kompresji w oknach, tak że tylko części muszą być obecne, ale wymaga to trochę fantazji w API zasobów i schematu kompresji, który działa dobrze z dostępem losowym. Teraz APK = = Zip z kompresją" deflate", więc to nie jest praktyczne.

Można zachować nieskompresowane zasoby, nadając im przyrostek typu pliku, który nie jest skompresowany (np.".png " lub ". mp3"). Możesz również być w stanie dodać je ręcznie podczas procesu budowania za pomocą" zip -0 " zamiast mieć je w pakiecie przez aapt. To prawdopodobnie zwiększy rozmiar Twojego APK.

 32
Author: fadden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-19 22:50:43

Jak Seva zasugerowała, możesz podzielić plik na kawałki. Użyłem tego do podzielenia mojego pliku 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++;  
    }  
  }  

Jeśli nie musisz ponownie łączyć plików w jeden plik na urządzeniu, po prostu użyj tego strumienia wejściowego, który łączy je w jeden w locie.

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

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

 8
Author: Oliver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-01 18:32:50

Une methode pas propre consiste a changer extence du fichier ttf a mp3

 7
Author: yassine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-09-01 07:39:06

Wiem, że to stare pytanie, ale pomyślałem o dobrym rozwiązaniu. Dlaczego nie zapisać wcześniej spakowanego pliku w folderze zasobu. Następnie ponieważ jest to już plik zip i dlatego skompresowany nie będzie musiał być ponownie skompresowany. Jeśli więc chcesz, aby plik został skompresowany, aby zmniejszyć rozmiar apk, ale nie chcesz zajmować się dzieleniem plików, myślę, że jest to łatwiejsze.

Gdy trzeba odczytać ten plik z urządzenia wystarczy owinąć strumień wejściowy w zipinputstream http://developer.android.com/reference/java/util/zip/ZipInputStream.html

 2
Author: Matt Wolfe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-24 01:05:49

Znalazłem inne rozwiązanie, może cię to zainteresuje.

W katalogu głównym Twoich źródeł, gdzie masz plik build.xml, możesz nadpisać -package-resources Cel w pliku custom_rules.xml, który jest używany do dodawania/modyfikowania celów w ant bez łamania czegokolwiek w standardowym systemie Android app build system.

Wystarczy utworzyć plik o tej zawartości:

<?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
Author: Ottavio Campana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-13 06:08:47

Dodaj rozszerzenie pliku to mp3.Używam folderu zasobów mydb. mp3in i kopiuję .to działa bez błędu.Pokaż sprawdź to.

 0
Author: santosh Kundkar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-15 10:32:55

Użycie GZIP byłoby inną metodą. wystarczy tylko owinąć InputStream wewnątrz GZIPInputStream.

użyłem tego do bazy danych, której rozmiar około 3.0 MB i wyjściowy plik kompresji był około 600KB.

  • do kopiowania DB w pierwszym uruchomieniu, gziped moje źródło .db file using GZIP narzędzie .
  • potem zmienił nazwę na .jpg w celu uniknięcia większej kompresji (procesy te są wykonywane przed skompilowaniem pliku APK).
  • następnie do odczytu skompresowanego pliku GZIP z assetss

I jej kopiowanie:

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
Author: VSB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-06 09:10:31

Ustaw bazę danych na wiele części za pomocą programu np. "Win Hex", możesz pobrać z Link

I kontynuuj Ładuj pliki większe niż 1M z folderu assets

 0
Author: Ehsan Jelodar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:01

Zamiast folderu assets umieściłem moje duże pliki w folderze raw. Dla mnie działa.

 0
Author: the100rabh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-13 07:20:20

Używam NetBeans do budowania pakietu i nie znalazłem jak zmienić ustawienia AAPT. Nie próbowałem png, ale mp3 są skompresowane. Mogę skompilować pakiet, a następnie wprowadzić folder zasobów z parametrem -0? jaka byłaby właściwa komenda do użycia?

 -1
Author: Syco,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-20 09:32:06