Загрузить файлы больше 1м от папке Assets

Я схожу с ума, я создал файловый объект, поэтому его можно прочитать С помощью ObjectInputStream, и я поместил папку assets. Метод работает с файлом меньше 1M и дает ошибку с большими файлами. Я читал, что это предел платформы Android, но я также знаю, что этого можно "легко" избежать. Те, кто скачал игру Reging Thunder, например, могут легко увидеть, что в их папке assets находится файл размером 18,9 м. Это мой код для чтения 1 объекта из a 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();

теперь у меня есть несжатый файл, и я могу использовать его, не беспокоясь об ошибке "этот файл не может быть открыт как дескриптор файла; это, вероятно, сжатый"

эта функция хорошо работает с файлами меньше 1M, с большими файлами возвращают java.Ио.IOException в строке " ObjectInputStream ois=новый ObjectInputStream (is);"

почему??

11 ответов


столкнулась с той же проблемой. Я разрезал свой файл 4MB на куски 1 MB, и при первом запуске я соединяю куски в папку данных на телефоне. В качестве дополнительного бонуса APK правильно сжат. Файлы chunk называются 1.ДБ, 2.дБ и т. д. Код выглядит так:

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

ограничение на сжатые активы. Если актив несжат, система может сопоставить данные файла с памятью и использовать систему подкачки виртуальной памяти Linux для извлечения или отбрасывания 4K фрагментов по мере необходимости. (Инструмент "zipalign" гарантирует, что несжатые активы выровнены по словам в файле, что означает, что они также будут выровнены в памяти при непосредственном сопоставлении.)

Если актив сжат, система должна распаковать все это в память. Если у вас есть актив 20MB, это означает, что 20 МБ физической памяти связано с вашим приложением.

В идеале система будет использовать какое-то оконное сжатие, так что должны присутствовать только части, но это требует некоторой причудливости в API активов и схемы сжатия, которая хорошо работает со случайным доступом. Прямо сейчас APK == Zip с сжатием" выкачать", так что это не практично.

вы можете сохранить свои активы несжатыми, предоставив им суффикс типа файла, который не сжимается (например,".png" или ".mp3"). Вы также можете добавить их вручную во время процесса сборки с помощью "zip -0" вместо того, чтобы связывать их aapt. Это, вероятно, увеличит размер вашего APK.


как предложил Сева, вы можете разделить файл на куски. Я использовал это, чтобы разделить мой файл 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++;  
    }  
  }  

Если вам не нужно снова объединять файлы в один файл на устройстве, просто используйте этот InputStream, который объединяет их в один на лету.

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

использование:
ObjectInputStream ois = new ObjectInputStream(new SplitFileInputStream("mytempfile", ".dat", 4, getAssets()));


une methode pas propre consiste a changer extention du fichier ttf a mp3


Я знаю, что это старый вопрос, но я подумал о хорошем решении. Почему бы не сохранить файл, уже предварительно сжатый в папке asset. Затем, поскольку это уже zip-файл и, следовательно, сжатый, его не нужно будет сжимать снова. Поэтому, если вы хотите, чтобы файл был сжат, чтобы уменьшить размер вашего apk, но вы не хотите иметь дело с разделением файлов, я думаю, что это проще.

когда вам нужно прочитать этот файл с устройства, просто оберните inputstream в zipinputstream http://developer.android.com/reference/java/util/zip/ZipInputStream.html


Я нашел другое решение, может быть, вы заинтересованы в нем.

в корне ваших источников, где у вас есть можно заменить на -package-resources цель custom_rules.xml файл, который используется для добавления/изменения целей в ant, не нарушая ничего в стандартной системе сборки приложений android.

просто создайте файл с таким содержимым:

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

добавить расширение файла mp3.Я использую mydb.mp3in ресурсы папки и копирования .этот запуск без ошибок.показать проверить его.


С помощью С помощью gzip был бы другой метод. вам нужно только обернуть InputStream внутри GZIPInputStream.

я использовал это для базы данных, размер которой около 3,0 МБ, а выходной файл сжатия - около 600 кб.

  • для копирования БД в firs run я gzipped мой источник .db файл с помощью С помощью gzip инструмент.
  • затем переименовал его .jpg во избежание больше компрессия (эти процессы выполняются перед компиляцией файла APK).
  • затем для чтения сжатого файла GZIP из assetss

и копирование:

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

установить базу данных на несколько частей с помощью программы e.g "Win Hex", вы можете скачать с ссылке

и дальше загрузка файлов размером более 1 м из папки активов


вместо папки assets я поместил свои большие файлы в папку raw. Это работает на меня.


Я использую NetBeans для создания пакета, и я не нашел, как изменить настройки AAPT. Я не пробовал png, но mp3 сжаты. Я могу скомпилировать пакет, а затем войти в папку assets с параметром -0? какую команду следует использовать?