前言
安卓文件永久存储分内部存储和外部存储。这里存储指ROM(断电仍记忆)而非运行内存(RAM断电记忆丢失)。
分类
- 内部存储(internal storage)
- 外部存储(external storage)
- external storage
- SDCard存储
介绍
内部存储
内部存储(app私有空间)不是内存,物理上为焊于手机中的闪存空间一部分(系统特殊位),绝对路径/data/data/app-package-name/
。内部存储文件默仅被你应用访问,卸载则内部存储文件被删。内部存储文件设可读,其它app知应用包名可访应用数据;文件私有则知包名亦不可访。内部存储空间是系统本身和系统应用程序主要数据存储地,十分有限,耗尽手机报废。尽量避用内部存储空间。Shared Preferences
和SQLite
数据库都于内部存储空间。内部存储用Context
获取和操作。
该目录自创目录files
、cache
、databases
、lib
、shared_prefs
,这些目录随app存储需求创,无存储需求不创。
外部存储
external storage
焊于手机中的闪存空间一部分,绝对路径/mnt/shell/emulated/0/
(不同系统有细微区别,但对调系统提供函数获路径无影响),通该路径可由file:///sdcard/xxx
获,文件xxx即储存/mnt/shell/emulated/0/
目录。
PC自带硬盘为内部存储,U盘或移动硬盘为外部存储。故容易这样理解安卓手机,认为机身固有存储为内部存储,扩展T卡为外部存储。如16GB版Nexus 4有16G内部存储,普通消费者可这样理解,但编程不能,这16GB仍外部存储。
所有安卓设备都有外部存储和内部存储,两名称源于早期设备,那时设备内部存储确实固定,外部存储确实可像U盘移动。后来很多中高端机都将机身存储扩展到8G+,存储概念分内部internal
和外部external
,事实都在手机内部。故不管安卓手机有可移动SDCard否,总有外部存储和内部存储。关键都通相同api访可移动SDCard或手机自带外部存储
。手机连电脑识别部分为外部存储。
SDCard
外部存储空间,自己所插SDCard。该空间不定总存,用前需判挂载否,外插SDCard根目录绝路径/storage/sdcard1/
。为简化只分内部存储空间和外部存储空间( 焊于手机内),可只认/data
目录存储空间为内部存储空间,/mnt/shell/emulated/0
目录空间为外部存储空间。
引申
外部存储分公有
和私有
。Google官方建议app数据应存储于外部存储私有目录app包名下,卸载app后一并删相关数据。直于/storage/sdcard目录创一应用文件夹则删应用时不删该文件夹。
公有
Environment.getExternalStorageDirectory()
外部存储第一层对象
复制代码
Environment.getExternalStoragePublicDirectory(String type)
DIRECTORY_ALARMS // 警报铃声
DIRECTORY_DCIM // 相机拍摄图和视频
DIRECTORY_DOWNLOADS // 下载文件
DIRECTORY_MOVIES // 电影
DIRECTORY_MUSIC // 音乐
DIRECTORY_NOTIFICATIONS // 通知音
DIRECTORY_PICTURES // 下载图
DIRECTORY_PODCASTS // 博客音频文件
DIRECTORY_RINGTONES // 铃声
复制代码
私有
Context.getExternalFilesDir()
/Android/data/应用包名/files/目录(通放一些长时保存数据)
复制代码
Context.getExternalCacheDir()
/Android/data/应用包名/cache/目录(通放临缓数据)
复制代码
示图
目录
外部存储
公有
华为、锤子正常,小米创失败
String fullPath = "Environment.getExternalStorageDirectory().getAbsolutePath()"+ File.separator;
File file = new File(fullPath , fileName);
if (!file.getParentFile().exists()) {
// 父目录不存则创父目录
file.getParentFile().mkdirs();
}
if (file.exists()) {
// 已存删旧文件
file.delete();
}
file.createNewFile();
复制代码
File file = new File("/sdcard/Dfs/");
if (!file.exists()) {
file.mkdirs();
}
// 文件夹创成后存数据
File file = new File(path + fileName);
复制代码
私有
华为、锤子、小米都正常
String fullPath = "context.getExternalFilesDir("DFS").getAbsolutePath()"+ File.separator;
File file = new File(fullPath , fileName);
if (!file.getParentFile().exists()) {
// 父目录不存则创父目录
file.getParentFile().mkdirs();
}
if (file.exists()) {
// 已存删旧文件
file.delete();
}
file.createNewFile();
复制代码
内部存储
华为、锤子、小米都正常
File file = new File("context.getFilesDir().getAbsoluteFile()", fileName);
if (!file.getParentFile().exists()) {
// 父目录不存则创父目录
file.getParentFile().mkdirs();
}
if (file.exists()) {
// 已存删旧文件
file.delete();
}
file.createNewFile();
复制代码
工具类
StorageHelper
package util;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.support.annotation.RequiresApi;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created on 2018/6/29.
*
* @desc 存储
*/
public class StorageHelper {
/**
* SDCard挂载否
*
* @return 挂载否
*/
private static boolean isMounted() {
// Environment.MEDIA_MOUNTED(SDCard已挂载)
// Environment.getExternalStorageState()(SDCard挂载状)
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
/**
* SDCard路径
*
* @return 路径
*/
private static String getSDCardPath() {
String path = null;
if (isMounted()) {
path = Environment.getExternalStorageDirectory().getAbsolutePath();
}
return path;
}
/**
* SDCard大小(单位兆)
*
* @return 大小
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public static long getSize() {
if (isMounted()) {
// statFs算文件系统存储空间大小
// 参数SDCard根目录
StatFs stat = new StatFs(getSDCardPath());
// 块数
long count = stat.getBlockCountLong();
// 块大小(单位字节)
long size = stat.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}
/**
* SDCard可用大小
*
* @return 可用大小
*/
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
public static long getAvailableSize() {
if (isMounted()) {
StatFs stat = new StatFs(getSDCardPath());
// 可用块数
long count = stat.getAvailableBlocksLong();
long size = stat.getBlockSizeLong();
return count * size / 1024 / 1024;
}
return 0;
}
/**
* 数据存到SDCard
*
* @param data 数据
* @param dir 路径
* @param fileName 文件名
* @return 存否
*/
public static boolean saveDataToSDCard(byte[] data, String dir, String fileName) {
boolean flag = false;
if (isMounted()) {
// 当前文件夹存否(不存则创)
String path = getSDCardPath() + File.separator + dir;
File file = new File(path);
// 文件夹不存
if (!file.exists()) {
file.mkdirs();
}
// 文件夹创成后存数据
file = new File(path + File.separator + fileName);
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(file));
bos.write(data);
bos.flush();
flag = true;
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (bos != null) {
bos.close();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return flag;
}
/**
* 读SDCard数据
*
* @param dir 路径
* @param fileName 文件名
* @return 数据
*/
public static byte[] getDataFromSDCard(String dir, String fileName) {
byte[] b = null;
if (isMounted()) {
String path = getSDCardPath() + File.separator + dir + File.separator + fileName;
File file = new File(path);
if (file.exists()) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
byte[] buf = new byte[1024 * 8];
int n;
while ((n = bis.read(buf)) != -1) {
baos.write(buf, 0, n);
baos.flush();
}
b = baos.toByteArray();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return b;
}
/**
* 据类型获公有路径
*
* @param type 类型
* @return 公有路径
*/
private static String getPublicPath(String type) {
if (isMounted()) {
return Environment.getExternalStoragePublicDirectory(type).getAbsolutePath();
}
return null;
}
/**
* 数据存到公有路径
*
* @param data 数据
* @param type 类型
* @param fileName 文件名
* @return 存否
*/
public static boolean saveDataToPublicPath(byte[] data, String type, String fileName) {
boolean flag = false;
if (isMounted()) {
// 公有路径
File file = new File(getPublicPath(type));
if (!file.exists()) {
file.mkdirs();
}
try {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(file, fileName)));
bos.write(data);
bos.flush();
flag = true;
bos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return flag;
}
/**
* 私有文件路径
*
* @param context 上下文对象
* @param dir 目录
* @return 私有文件路径
*/
private static String getPrivateFilePath(Context context, String dir) {
if (isMounted()) {
return context.getExternalFilesDir(dir).getAbsolutePath();
}
return null;
}
/**
* 数据存到私有文件路径
*
* @param data 数据
* @param context 上下文对象
* @param dir 目录
* @param fileName 文件名
* @return 存否
*/
public static boolean saveDataToPrivateFilePath(byte[] data, Context context, String dir, String fileName) {
boolean flag = false;
if (isMounted()) {
File file = new File(getPrivateFilePath(context, dir));
if (!file.exists()) {
file.mkdirs();
}
try {
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(file, fileName)));
bos.write(data);
bos.flush();
flag = true;
bos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return flag;
}
/**
* 数据存到私有缓存路径
*
* @param data 数据
* @param fileName 文件名
* @param context 上下文对象
* @return 存否
*/
public static boolean saveDataToPrivateCachePath(byte[] data, String fileName, Context context) {
BufferedOutputStream bos = null;
if (isMounted()) {
File file = context.getExternalCacheDir();
try {
bos = new BufferedOutputStream(new FileOutputStream(new File(file, fileName)));
bos.write(data);
bos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return false;
}
/**
* @param context 上下文对象
* @param dir 目录
* @return 文件路径
*/
public static String getFilePath(Context context, String dir) {
String directoryPath;
// SDCard可用否
if (isMounted()) {
directoryPath = context.getExternalFilesDir(dir).getAbsolutePath();
/*directoryPath = context.getExternalCacheDir().getAbsolutePath();*/
} else {
// 无内存卡即存机身内存
directoryPath = context.getFilesDir() + File.separator + dir;
/*directoryPath = context.getCacheDir() + File.separator + dir;*/
}
File file = new File(directoryPath);
if (!file.exists()) {
// 文件目录存否
file.mkdirs();
}
return directoryPath;
}
}
复制代码
FileUtils
package util;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Log;
import java.io.Closeable;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.util.Locale;
import value.Magic;
/**
* Created on 2017/12/6.
*
* @desc file manipulation
*/
public class FileUtils {
/**
* TAG for log messages.
*/
private static final String TAG = "FileUtils";
private FileUtils() {
}
/**
* 据uri获真路径
*
* @param context 上下文
* @param contentUri contentUri
* @return 据URI真路径
*/
public static String getRealPathFromUri(Context context, Uri contentUri) {
Cursor cursor = null;
try {
String[] pro = {MediaStore.Images.Media.DATA};
cursor = context.getContentResolver().query(contentUri, pro, null, null, null);
int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(columnIndex);
} finally {
if (cursor != null) {
cursor.close();
}
}
}
/**
* 文件存否
*
* @param filePath filePath
* @return 据路径存否
*/
public static boolean isFileExistByPath(final String filePath) {
return isFileExist(getFileByPath(filePath));
}
/**
* 文件存否
*
* @param file file
* @return 存否
*/
private static boolean isFileExist(final File file) {
return file != null && file.exists();
}
/**
* 据文件路径获文件
*
* @param filePath filePath
* @return file
*/
private static File getFileByPath(final String filePath) {
return isSpace(filePath) ? null : new File(filePath);
}
private static boolean isSpace(final String s) {
if (s == null) {
return true;
}
for (int i = 0, len = s.length(); i < len; ++i) {
if (!Character.isWhitespace(s.charAt(i))) {
return false;
}
}
return true;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
* @author paulburke
*/
private static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
* @author paulburke
*/
private static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
* @author paulburke
*/
private static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
private static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
/**
* Get the value of the data column for this Uri.
* This is useful for MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
* @author paulburke
*/
private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int columnIndex = cursor.getColumnIndexOrThrow(column);
return cursor.getString(columnIndex);
}
} catch (IllegalArgumentException ex) {
Log.i(TAG, String.format(Locale.getDefault(), "getDataColumn: _data - [%s]", ex.getMessage()));
} finally {
if (cursor != null) {
cursor.close();
}
}
return null;
}
/**
* Get a file path from a Uri.
* This will get the the path for Storage Access Framework Documents, as well as the _data field for the MediaStore and other file-based ContentProviders.
* Callers should check whether the path is local before assuming it represents a local file.
* 4.4选本地文件返uri如content://com.android.providers.media.documents/document/video%3A415296转绝对路径storage/emulated/0/DCIM/Camera/VID_20180312_160348.mp4
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
@SuppressLint("NewApi")
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if (Magic.STRING_PRIMARY.equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if (Magic.STRING_IMAGE.equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if (Magic.STRING_VIDEO.equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if (Magic.STRING_AUDIO.equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if (Magic.STRING_CONTENT.equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri)) {
return uri.getLastPathSegment();
}
return getDataColumn(context, uri, null, null);
}
// File
else if (Magic.STRING_FILE.equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Copies one file into the other with the given paths.
* In the event that the paths are the same, trying to copy one file to the other will cause both files to become null.
* Simply skipping this step if the paths are identical.
*/
public static void copyFile(@NonNull String pathFrom, @NonNull String pathTo) throws IOException {
if (pathFrom.equalsIgnoreCase(pathTo)) {
return;
}
FileChannel outputChannel = null;
FileChannel inputChannel = null;
try {
inputChannel = new FileInputStream(new File(pathFrom)).getChannel();
outputChannel = new FileOutputStream(new File(pathTo)).getChannel();
inputChannel.transferTo(0, inputChannel.size(), outputChannel);
inputChannel.close();
} finally {
if (inputChannel != null) {
inputChannel.close();
}
if (outputChannel != null) {
outputChannel.close();
}
}
}
/**
* 删文件或文件夹
*
* @param fileName 所删文件名
* @return 成true败false
*/
public static boolean delete(String fileName) {
File file = new File(fileName);
if (!file.exists()) {
return false;
} else {
if (file.isFile()) {
return deleteFile(fileName);
} else {
return deleteDirectory(fileName);
}
}
}
/**
* 删单文件
*
* @param fileName 所删文件名
* @return 成true败false
*/
private static boolean deleteFile(String fileName) {
File file = new File(fileName);
// 路径对应文件存在且是文件则直删
if (file.exists() && file.isFile()) {
if (file.delete()) {
System.out.println("删单文件" + fileName + "成功");
return true;
} else {
System.out.println("删单文件" + fileName + "失败");
return false;
}
} else {
System.out.println("删单文件失败:" + fileName + "不存在");
return false;
}
}
/**
* 删目录及目录下文件
*
* @param dir 所删目录文件路径
* @return 成true败false
*/
private static boolean deleteDirectory(String dir) {
// dir不以文件分隔符结尾则自动添文件分隔符
if (!dir.endsWith(File.separator)) {
dir = dir + File.separator;
}
File dirFile = new File(dir);
// dir对应文件不存或非目录则退出
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
LogUtils.e("删目录失败:" + dir + "不存在");
return false;
}
boolean flag = true;
// 删文件夹所有文件(含子目录)
File[] files = dirFile.listFiles();
for (File file : files) {
// 删子文件
if (file.isFile()) {
flag = deleteFile(file.getAbsolutePath());
if (!flag) {
break;
}
}
// 删子目录
else if (file.isDirectory()) {
flag = deleteDirectory(file.getAbsolutePath());
if (!flag) {
break;
}
}
}
if (!flag) {
LogUtils.e("删目录失败");
return false;
}
// 删当前目录
if (dirFile.delete()) {
LogUtils.e("删目录" + dir + "成功");
return true;
} else {
return false;
}
}
/**
* 复制文件至新路径(Android N+)
*
* @param context 上下文
* @param contentUri 内容标识符
* @return 新路径
*/
public static String copyFileToNewPathAfterAndroidN(Context context, Uri contentUri) {
// copy file and send new file path
String fileName = getFileName(contentUri);
if (!TextUtils.isEmpty(fileName)) {
File copyFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "video" + File.separator + fileName);
copy(context, contentUri, copyFile);
return copyFile.getAbsolutePath();
}
return null;
}
private static String getFileName(Uri uri) {
if (uri == null) {
return null;
}
String fileName = null;
String path = uri.getPath();
int cut = path.lastIndexOf('/');
if (cut != -1) {
fileName = path.substring(cut + 1);
}
return fileName;
}
private static void copy(Context context, Uri srcUri, File dstFile) {
try {
InputStream inputStream = context.getContentResolver().openInputStream(srcUri);
if (inputStream == null) {
return;
}
OutputStream outputStream = new FileOutputStream(dstFile);
try {
IoUtils.copy(inputStream, outputStream);
} catch (Exception e) {
e.printStackTrace();
}
inputStream.close();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 路径
* 7.0uri转图路径遇java.lang.IllegalArgumentException: column '_data' does not exist
*
* @param context 上下文
* @param contentResolver 内容提供者
* @param uri 标识符
* @return 路径
*/
private static String getFromMediaUri(Context context, ContentResolver contentResolver, Uri uri) {
if (uri == null) {
return null;
}
FileInputStream input = null;
FileOutputStream output = null;
try {
ParcelFileDescriptor pfd = contentResolver.openFileDescriptor(uri, "r");
if (pfd == null) {
return null;
}
FileDescriptor fd = pfd.getFileDescriptor();
input = new FileInputStream(fd);
String tempFilename = getTempFilename(context);
output = new FileOutputStream(tempFilename);
int read;
byte[] bytes = new byte[4096];
while ((read = input.read(bytes)) != -1) {
output.write(bytes, 0, read);
}
return new File(tempFilename).getAbsolutePath();
} catch (Exception ignored) {
ignored.getStackTrace();
} finally {
closeSilently(input);
closeSilently(output);
}
return null;
}
private static String getTempFilename(Context context) throws IOException {
File outputDir = context.getCacheDir();
File outputFile = File.createTempFile("image", "tmp", outputDir);
return outputFile.getAbsolutePath();
}
private static void closeSilently(@Nullable Closeable c) {
if (c == null) {
return;
}
try {
c.close();
} catch (Throwable t) {
// Do nothing
}
}
}
复制代码
辅助
package util;
import android.util.Log;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Created on 2018/8/16.
*
* @desc IoUtils
*/
public class IoUtils {
private static final int BUFFER_SIZE = 1024 * 2;
private IoUtils() {
// Utility class.
}
public static int copy(InputStream input, OutputStream output) throws Exception, IOException {
byte[] buffer = new byte[BUFFER_SIZE];
BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
int count = 0, n;
try {
while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
out.write(buffer, 0, n);
count += n;
}
out.flush();
} finally {
try {
out.close();
} catch (IOException e) {
Log.e(e.getMessage(), String.valueOf(e));
}
try {
in.close();
} catch (IOException e) {
Log.e(e.getMessage(), String.valueOf(e));
}
}
return count;
}
}
复制代码