我正在通过从一个文件夹到另一个文件夹的线程移动文件(大约100-2000个文件,每个大小100-200KB)。一切顺利,但在一些三星&带有 sdcard 的LG设备,在复制后突然发现全部或部分设备丢失。
每次都不会发生这种情况,但大约每20次发生一次。
到目前为止,我尝试了3种技术:
public void copyMethodA(File src, File dst){
if(!dst.exists()){
src.renameTo(dst);
}
}
copyMethodA();在大多数情况下导致文件丢失。
public void copyMethodB(File sourceFile, File destFile) throws IOException {
if (!destFile.exists()) {
destFile.createNewFile();
}
try {
FileChannel source = new FileInputStream(sourceFile).getChannel();
FileChannel destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
source.close();
destination.close();
}
}
copyMethodB();导致文件丢失的次数比A少。
public void copyMethodC(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
byte[] buf = new byte[10240];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
copyMethodC();很少导致文件丢失。 因此目前使用此。
所有3种方法都能很好地工作,而Xperia C& C Nexus 5(均使用内部存储) 但在LG Optimus One(使用SD卡)和一些三星设备(使用内部或SD卡)上观察到文件丢失
有关我测试过的设备的信息:
(我猜这个问题与使用的Android版本无关)
我正在避免使用庞大的第三方文件IO API,因为我的Android应用程序的大小只有300KB。使用像Apache commons.io这样的API会使它膨胀到大约2.5MB
还有其他安全,安全和更好的复制文件的方法?
感谢。
答案 0 :(得分:1)
我认为你应该这样:
您应该检查renameTo
的返回值,因为javadoc表示它的失败原因很多。
如果renameTo
调用失败,请使用第三种方法,使用try / catch块在读取/写入流时捕获IOException,并确保在复制成功时仅删除源文件。然后,您可以检查异常以了解副本失败的原因,并可能稍后重试。
我正在这样做(使用1024字节的缓冲区,比如@beni的答案)来复制几百个文件,我从未见过任何损失。
答案 1 :(得分:0)
我正在使用此功能并始终有效。我在Nexus 5上测试了这段代码.in.read(buf)方法在文件末尾返回-1,在其他情况下返回readed的字节数。所以,试试吧。
public static void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}