Android 从资产文件夹加载大于1M的文件
我快发疯了,我创建了一个文件对象,这样就可以用ObjectInputStream读取它,然后我把资产文件夹放在了这里。 该方法适用于小于1M的文件,对于较大的文件,会给出错误。 我读到这是Android平台的一个限制,但我也知道这是可以“轻松”避免的。 例如,那些下载了游戏Reging Thunder的人可以很容易地看到,在他们的资产文件夹中有一个18.9M大的文件。 这是我从ObjectInputStream读取1对象的代码Android 从资产文件夹加载大于1M的文件,android,load,inputstream,assets,objectinputstream,Android,Load,Inputstream,Assets,Objectinputstream,我快发疯了,我创建了一个文件对象,这样就可以用ObjectInputStream读取它,然后我把资产文件夹放在了这里。 该方法适用于小于1M的文件,对于较大的文件,会给出错误。 我读到这是Android平台的一个限制,但我也知道这是可以“轻松”避免的。 例如,那些下载了游戏Reging Thunder的人可以很容易地看到,在他们的资产文件夹中有一个18.9M大的文件。 这是我从ObjectInputStream读取1对象的代码 File f = File.createTempFile("myte
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的文件,较大的文件返回
“ObjectInputStream ois=new ObjectInputStream(is);”行上的java.io.IOException
为什么???我将大文件放在原始文件夹中,而不是资产文件夹。它对我有用 限制在压缩资产上。如果资产未压缩,则系统可以内存映射文件数据,并使用Linux虚拟内存分页系统根据需要拉入或丢弃4K块。(zipalign工具确保未压缩的资源在文件中与单词对齐,这意味着它们在直接映射时也将在内存中对齐。) 如果资产被压缩,系统必须将整个内容解压缩到内存中。如果您有20MB的资产,这意味着应用程序占用了20MB的物理内存 理想情况下,系统将采用某种类型的窗口压缩,以便只需要显示部分,但这需要资产API中的一些想象力和一种能够与随机访问一起工作的压缩方案。现在,APK==Zip使用“deflate”压缩,所以这是不实际的
你可以通过给你的资产一个不被压缩的文件类型后缀(例如“.png”或“.mp3”)来保持你的资产不被压缩。您还可以在构建过程中使用“zip-0”手动添加它们,而不是让aapt将它们捆绑起来。这可能会增加APK的大小。我使用NetBeans构建包,但我没有找到如何更改AAPT的设置。 我没有试过png,但mp3是压缩的。 我可以编译包,然后输入参数为-0的assets文件夹?
正确的命令是什么?面临同样的问题。我已经将4MB的文件分割成1MB的块,第一次运行时,我将这些块连接到手机上的数据文件夹中。作为额外的奖励,APK被适当压缩。区块文件称为1.db、2.db等。代码如下:
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();
}
File Path=Ctxt.getDir(“数据”,0);
File DBFile=新文件(路径“database.db”);
如果(!DBFile.exists()| | DatabaseNeedsUpgrade)//需要复制。。。
CopyDatabase(Ctxt,DBFile);
静态私有void CopyDatabase(Context Ctxt,File DBFile)引发IOException
{
AssetManager资产=Ctxt.getAssets();
OutputStream outstream=新文件OutputStream(DBFile);
DBFile.createNewFile();
字节[]b=新字节[1024];
int i,r;
字符串[]assetfiles=assets.list(“”);
Arrays.sort(assetfiles);
对于(i=1;i将文件扩展名更改为.mp3,就像Seva建议的那样,您可以将文件拆分为多个块。我用这个来拆分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++;
}
}
publicstaticvoidmain(字符串[]args)引发异常{
String base=“tracks”;
字符串ext=“.dat”;
int split=1024*1024;
字节[]buf=新字节[1024];
int chunkNo=1;
文件填充=新文件(基本+外部);
FileInputStream fis=新的FileInputStream(填充);
虽然(正确){
FileOutputStream fos=新的FileOutputStream(新文件(base+chunkNo+ext));
对于(int i=0;i
如果您不需要在设备上再次将这些文件合并为单个文件,只需使用这个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;
}
}
import java.io.IOException;
导入java.io.InputStream;
导入android.content.res.AssetManager;
公共类SplitFileInputStream扩展InputStream{
私有字符串基名称;
私有字符串扩展;
私人资产管理人am;
私有整数块;
private int currentChunk=1;
私有输入流currentIs=null;
public SplitFileInputStream(String baseName、String ext、int numberOfChunks、AssetManager am)抛出IOException{
this.baseName=baseName;
this.am=am;
this.numberOfChunks=numberOfChunks;
this.ext=ext;
currentIs=am.open(baseName+currentcunk+ext,AssetManager.ACCESS\u流媒体);
}
@凌驾
public int read()引发IOException{
int read=currentIs.read();
如果(读取==-1&¤tChunk<?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>
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();
}