我正在从互联网上下载文件,并将流式数据保存到getFilesDir()给出的应用内部存储空间中的临时文件中。
下载完成后,我需要将临时文件移动到外部存储器上的下载目录(通常是SD卡)。但由于某种原因,File.renameTo()不适用于此。我猜这是一个问题,因为它是两个独立的文件系统,但我仍然可以直接下载到SD卡,文件URI是正确的。
还有另一种简单快捷的方法可以将该文件从内部存储器传输到外部,还是我必须进行字节流复制并删除原始文件?
答案 0 :(得分:82)
使用以下代码将文件从内部存储器复制到SD卡,反之亦然:
public static void copyFile(File src, File dst) throws IOException
{
FileChannel inChannel = new FileInputStream(src).getChannel();
FileChannel outChannel = new FileOutputStream(dst).getChannel();
try
{
inChannel.transferTo(0, inChannel.size(), outChannel);
}
finally
{
if (inChannel != null)
inChannel.close();
if (outChannel != null)
outChannel.close();
}
}
而且 - 它有效......
答案 1 :(得分:12)
内部和外部存储器是两个不同的文件系统。因此renameTo()失败。
您必须复制文件并删除原始文件
答案 2 :(得分:10)
复制文件后(如@barmaley的精彩答案所示),请勿忘记将其公开到设备的图库,以便用户稍后查看。
必须手动完成的原因是
Android仅在重新启动和重新安装时运行完整的媒体扫描 SD卡
(如this guide所示)。
更简单的方法是通过发送广播来调用扫描:
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
intent.setData(Uri.fromFile(outputFile));
context.sendBroadcast(intent);
瞧!您现在可以在设备的图库中查看文件。
答案 3 :(得分:3)
使用自己的函数进行复制的另一种方法是在名为copyFile的函数中使用Apache的库“FileUtils”:
FileUtils.copyFile(src, dst, true);
答案 4 :(得分:0)
对@ barmaley的代码进行了一些微不足道的修改
public boolean copyFile(File src, File dst) {
boolean returnValue = true;
FileChannel inChannel = null, outChannel = null;
try {
inChannel = new FileInputStream(src).getChannel();
outChannel = new FileOutputStream(dst).getChannel();
} catch (FileNotFoundException fnfe) {
Log.d(logtag, "inChannel/outChannel FileNotFoundException");
fnfe.printStackTrace();
return false;
}
try {
inChannel.transferTo(0, inChannel.size(), outChannel);
} catch (IllegalArgumentException iae) {
Log.d(logtag, "TransferTo IllegalArgumentException");
iae.printStackTrace();
returnValue = false;
} catch (NonReadableChannelException nrce) {
Log.d(logtag, "TransferTo NonReadableChannelException");
nrce.printStackTrace();
returnValue = false;
} catch (NonWritableChannelException nwce) {
Log.d(logtag, "TransferTo NonWritableChannelException");
nwce.printStackTrace();
returnValue = false;
} catch (ClosedByInterruptException cie) {
Log.d(logtag, "TransferTo ClosedByInterruptException");
cie.printStackTrace();
returnValue = false;
} catch (AsynchronousCloseException ace) {
Log.d(logtag, "TransferTo AsynchronousCloseException");
ace.printStackTrace();
returnValue = false;
} catch (ClosedChannelException cce) {
Log.d(logtag, "TransferTo ClosedChannelException");
cce.printStackTrace();
returnValue = false;
} catch (IOException ioe) {
Log.d(logtag, "TransferTo IOException");
ioe.printStackTrace();
returnValue = false;
} finally {
if (inChannel != null)
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
if (outChannel != null)
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return returnValue;
}
答案 5 :(得分:0)
想象一下:
尝试使用此代码:
public void moveIn (String pathInternal, String pathExternal) {
File fInternal = new File (pathInternal);
File fExternal = new File (pathExternal);
if (fInternal.exists()) {
fInternal.renameTo(fExternal);
}
}
答案 6 :(得分:0)
您可以使用 byte []
进行操作在你的班级中定义:
public static final String DATA_PATH =
Environment.getExternalStorageDirectory().toString() + "/MyAppName/";
然后:
AssetManager assetManager = context.getAssets();
InputStream in = assetManager.open("data/file.txt");
OutputStream out = new FileOutputStream(DATA_PATH + "data/file.txt");
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
答案 7 :(得分:-1)
对于移动文件,最好的方法是使用不同的路径和名称重命名它的路径 例如:
File from = new File(Environment.getExternalStorage().getAbsolutePath()+"/kaic1/imagem.jpg");
File to = new File(Environment.getExternalStorage().getAbsolutePath()+"/kaic2/imagem.jpg");
from.renameTo(to);