在复制目录和文件时处理 IO 异常的最佳实践?



示例代码如下。 它会将目标文件和目录从一个位置复制到另一个位置。 在通过网络复制文件时处理 IO 异常的最佳做法是什么?

我使用了printStackTrace((,但感觉这只是一个更好的解决方案的占位符。 日志记录是答案吗,除了日志记录之外,是否应该还有另一个步骤来实际"处理"错误?

感谢您的反馈。

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
This is a test program to copy a directory(s) & file(s) from one location to another.
*/
public class CopyTest{
public static void main(String[] args) {
//Declarations 
String sourcePath = "I:\MB\PO"; 
String destPath = "C:\testPO\";  
System.out.println("Source path:  " + sourcePath);  
System.out.println("Destination path:  " + destPath);  
File source = new File(sourcePath);  
File dest = new File(destPath);  
//Process
//Call to method copyUsingStream
long start = System.nanoTime(); //start recording how much time the copy takes.
copyUsingStream(source, dest);  //method to copy the directory/files.
System.out.println("Time taken to copy the file: "+(System.nanoTime() -start) + " nanoseconds");
} //end main method
/**
The copyUsingStream method is a recursive method to copy folders and files from one location to another.
*/
private static void copyUsingStream(File source, File dest) {   
if (!source.isDirectory()){ 
// If source is a file -> copy it to the new folder
InputStream inStream = null;
OutputStream outStream = null;
try {
inStream = new FileInputStream(source);
outStream = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, length);
}
} catch(IOException ioe) {
ioe.printStackTrace();
} finally {
try{
inStream.close();
outStream.close();
System.out.println("File copied from " + source + " to " + dest + "successfully");
} catch(IOException ioe2) {
ioe2.printStackTrace();
}
} 
} else {
//If a directory -> create the directory inside the new destination
//List all contents
if (!dest.exists()) {
dest.mkdir();
System.out.println("Directory copied from " + source + " to " + dest + "successfully");
}
String folder_contents[] = source.list();
for (String file : folder_contents) {
File srcFile = new File(source, file);
File destFile = new File(dest, file);
copyUsingStream(srcFile, destFile);
}
}
} //end method copyUsingStream
} //end class CopyTest

没有渔获物的方法:

private static void copyUsingStream(File source, File dest) throws IOException {   
if (!source.isDirectory()){ 
// If source is a file -> copy it to the new folder
InputStream inStream = null;
OutputStream outStream = null;
try {
inStream = new FileInputStream(source);
outStream = new FileOutputStream(dest);
byte[] buffer = new byte[1024];
int length;
while ((length = inStream.read(buffer)) > 0) {
outStream.write(buffer, 0, length);
}
} finally {
inStream.close();
outStream.close();
System.out.println("File copied from " + source + " to " + dest + "successfully");
} 
} else {
//If a directory -> create the directory inside the new destination
//List all contents
if (!dest.exists()) {
dest.mkdir();
System.out.println("Directory copied from " + source + " to " + dest + "successfully");
}
String folder_contents[] = source.list();
for (String file : folder_contents) {
File srcFile = new File(source, file);
File destFile = new File(dest, file);
copyUsingStream(srcFile, destFile);
}
}
} //end method copyUsingStream

这在很大程度上取决于您的应用程序。

无论如何,继续运行的应用程序(例如 Web 服务器、守护程序和批处理器(通常会将此类错误与时间戳、线程 ID 和其他可能的有用信息一起记录在文件中。

我对两个日志文件的组合有很好的经验。

  1. myapp.log只接收重要消息,通常是警告和错误。此文件适用于普通用户和系统操作员。
  2. debug.log适用于开发人员。它提供错误发生前的调试消息,但只要一切正常,就没有消息。要启用此功能,需要内存缓冲区。

如果您对该缓冲区感兴趣,可以查看 http://stefanfrings.de/bfUtilities/index.html .该网站是德语的,但图书馆及其文档是英文的。

在桌面 GUI 应用程序上,当错误中止请求的操作时,最好在弹出窗口中显示简短的错误消息,并在可展开的框中隐藏详细信息(堆栈跟踪(。不要忘记清楚地告诉用户哪个操作失败。异常本身对开发人员来说可能足够清楚,但普通用户期望的是技术性较低的文本。例如:"从服务加载天气信息 weather.com 失败:连接失败",后跟堆栈跟踪。

对于立即停止的控制台应用程序,我更喜欢直接在屏幕上看到堆栈跟踪,如printStackTrace()编写的那样。

正如Stefan所说,这取决于应用程序。

一个好的经验法则是:不要捕获异常,除非您准备执行特定操作(除了打印或记录它之外(,或者没有可以传播它的调用方。

如果您有用于复制文件的常规方法,则该方法不应假设调用它的原因。 它的工作是复制文件。 仅当它成功完成该任务时,它才应返回。 如果不成功,则应引发异常而不是返回。

因此,对于常规复制方法,您可能希望将throws IOException添加到方法签名中,并且在方法本身中具有零 try/catch 块。 这使调用方可以决定如何处理故障。 GUI 应用程序可能会显示错误对话框。 服务可能只是记录异常,稍后重试。

您自己应该只在尽可能高的级别捕获并记录异常。 GUI 应用程序会在显示错误对话框之前立即记录它。 (您可能还希望在对话框中的可展开的"显示详细信息"部分中包含堆栈跟踪的文本。 服务可能具有主循环或主执行方法,其中没有可以向其传播异常的更高调用方,因此除了记录它之外别无他法。

最新更新