android中数据的分包

在Android 2.3之后,从apk拷贝数据的大小限制为1M。针对这一问题,本文介绍了如何将大文件如5M的apk和30M的数据库分包,再重新组合到SD卡上的详细过程。通过平均分段读取并写入多个小文件,然后逐一合并成目标文件,最后删除临时小文件,成功规避了系统限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

之前在开发中,遇到了一个问题,就是在项目assets下有一个apk需要在应用启动时安装到设备中,实现的思路是需要首先将apk拷贝到sdcard中,然后执行安装操作,还有一个问题就是项目中的数据库也需要放在sdcard中,这个apk大约有5M左右,我的数据库大约有30M左右,接下来我就按照普通的I/O流拷贝:

public static boolean copyDataToSD(Context context, String fileName, File strOutFile) {
        InputStream myInput = null;
        OutputStream myOutput = null;
        try {
            myOutput = new FileOutputStream(strOutFile);
            myInput =context.getAssets().open(fileName);
            byte[] buffer = new byte[1024];
            int length = myInput.read(buffer);
            while (length > 0) {
                myOutput.write(buffer, 0, length);
                length = myInput.read(buffer);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (myOutput != null) {
                    myOutput.flush();
                    myOutput.close();
                }
                if (myInput != null)
                    myInput.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

但是在执行上述代码时,却报错了,经过查询才知道android2.3之后要求从apk拷贝出去的数据必须小于1M,坑爹呀!!!
那么,我们只能将数据分解了!,直接看完整的代码:

public static List<String> splitBigFile(Context context, String fileName, String formatType, String dirName) {
        //需要分割的文件的文件名称
        String base = fileName;
        //需要分割的文件的后缀名
        String ext = formatType;

        List<String> list = new ArrayList<>();

        InputStream inputStream = null;

        //以每个小文件1024*1024字节即1M的标准来分割
        int split = 1024 * 1024;
        byte[] buf = new byte[1024];
        int num = 1;
        try {
            //需要分割的文件的文件
            inputStream = context.getAssets().open(fileName + formatType);
            File fileDir = new File(SDCardUtils.getSDCardPath() + File.separator + dirName);
            if (!fileDir.exists()) {
                fileDir.mkdir();
            }
            while (true) {
                //以"demo"+num+".db"方式来命名小文件即分割后为demo1.db,demo2.db,。。。。。。
                File file = new File(SDCardUtils.getSDCardPath() + File.separator + dirName + File.separator + base + num + ext);
                if (!file.exists()) {
                    file.createNewFile();
                }
                list.add(file.getPath());
                FileOutputStream fos = new FileOutputStream(file);
                for (int i = 0; i < split / buf.length; i++) {
                    int read = inputStream.read(buf);
                    fos.write(buf, 0, read);
                    // 判断大文件读取是否结束
                    if (read < buf.length) {
                        inputStream.close();
                        fos.close();
                        return list;
                    }
                }
                num++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    public static boolean mergeFile(Object[] partFileList, String dst, String formatType, String dirName) {
        try {
            OutputStream out = new FileOutputStream(dst);
            byte[] buffer = new byte[1024];
            InputStream in;
            int readLen = 0;
            for (int i = 0; i < partFileList.length; i++) {
                // 获得输入流 ,注意文件的路径
                String str = partFileList[i].toString();
                if (partFileList[i].toString().endsWith(formatType)) {
                    in = new FileInputStream(new File(partFileList[i].toString()));
                    while ((readLen = in.read(buffer)) != -1) {
                        out.write(buffer, 0, readLen);
                    }
                    out.flush();
                    in.close();
                }
            }
            // 把所有小文件都进行写操作后才关闭输出流,这样就会合并为一个文件了
            out.close();

            deleteFolder(SDCardUtils.getSDCardPath() + File.separator + dirName);

            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

public static void deleteFolder(String folderPath) {
      File localFolder = new File(folderPath);
      if (localFolder.isDirectory()) {
            String[] childrenStrings = localFolder.list();
            int length = childrenStrings.length;
            for (int i = 0; i < length; i++) {
                File temp = new File(localFolder, childrenStrings[i]);
                if (temp.isDirectory()) {
                    deleteFolder(temp.getName());
                } else {
                    temp.delete();
                }
            }
            localFolder.delete();
        }
    }

通过上面的代码可以看出实现的思路是:
a.将源文件平均1M大小地分解读取,然后每M流分别写入sdcard中一个小文件中,文件路径存放在一个集合中,这些小文件的命名分别问类似编号:xxx1.db,xxx2.db….等等;
b.在sdcard中创建一个要生成的目标文件,然后通过遍历这些小文件,将每个小文件写入目标文件中;
c.最后关闭流对象,删除这些小文件。

最后,在需要调用的地方:

//第一个参数是上下文,第二个参数是assets下数据包的名字,第三个参数表示数据包的后缀,第四个参数表示要在sdcard中临时存放分解的小文件的文件夹
List<String> strings =CopyDataToSDUtils.splitBigFile(MainActivity.this, "xxx", ".apk", "xxxapk");
boolean b =CopyDataToSDUtils.mergeFile(strings.toArray(), apkPath, ".apk", "hdpapk");
if (b) {
   Log.d(MainActivity.class.getName(),"拷贝成功");
}else{
   Log.d(MainActivity.class.getName(),"拷贝失败");
}

小结:以上是我个人在开发中的一个小插曲,通常我们在例如上传或下载大文件时,为了保证数据包能快速安全并且完整地到达,也会采用分包的处理方式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值