Наилучшая практика обработки исключений ввода-вывода при копировании каталога (ов) и файла (ов)? - PullRequest
0 голосов
/ 07 февраля 2020

Пример кода ниже. Он скопирует целевые файлы и каталог из одного места в другое. Что считается лучшей практикой для обработки исключений ввода-вывода при копировании файлов по сети?

Я использовал 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

Ответы [ 2 ]

0 голосов
/ 08 февраля 2020

Как сказал Стефан, это зависит от приложения.

Хорошее практическое правило: не создавайте исключение, если вы не готовы предпринять конкретное действие c, выходящее за рамки его печати или регистрации. или нет вызывающего абонента, которому вы можете распространять его.

Если у вас есть общий метод для копирования файла, этот метод не должен делать предположения о том, почему он вызывается. Его работа - копировать файл. Он должен вернуться только в случае успеха в этой задаче. Если это не удастся, он должен генерировать исключение, а не возвращать.

Так что для обычного метода копирования вы хотели бы добавить throws IOException к сигнатуре метода и иметь нулевые блоки try / catch в сам метод. Это позволяет звонящим решить, как обработать ошибку. Приложение GUI может отображать диалоговое окно с сообщением об ошибке. Служба может просто зарегистрировать исключение и повторить попытку позже.

Вы сами должны фиксировать и регистрировать исключение только на максимально возможном уровне. Приложение GUI запишет его прямо перед отображением диалога об ошибке. (Возможно, вы также захотите включить текст трассировки стека в диалоговом окне в расширяемый раздел «Показать подробности».) У службы может быть основной метод l oop или основной метод выполнения, где нет более высокого вызывающего абонента, которому Исключение можно распространить, поэтому ничего не нужно делать, кроме как зарегистрировать его.

0 голосов
/ 07 февраля 2020

Это сильно зависит от вашего приложения.

Приложения, которые все равно продолжают работать (например, веб-серверы, демоны и пакетные процессоры), обычно регистрируют такие ошибки в файле вместе с отметкой времени, идентификатором потока и, возможно, другой полезной информацией.

У меня было очень хороший опыт работы с комбинацией двух файлов журнала.

  1. myapp.log получает только важные сообщения, обычно предупреждения и ошибки. Этот файл для обычного пользователя и системного оператора.
  2. debug.log для разработчика. Он предоставляет отладочные сообщения за время до возникновения ошибки, но никаких сообщений, пока все работает нормально. Для этого требуется буфер памяти.

Если вы заинтересованы в этом буфере, вы можете взглянуть на http://stefanfrings.de/bfUtilities/index.html. Веб-сайт немецкий, но библиотека и его документация на английском языке sh.

В настольном приложении GUI, когда ошибка прерывает запрошенную операцию, было бы неплохо показать короткие сообщения об ошибке в всплывающее окно и скрыть детали (трассировка стека) в раскрывающемся окне. Не забудьте четко сказать пользователю, какая операция не удалась. Само по себе исключение может быть достаточно ясным для вашего разработчика, но обычные пользователи ожидают менее технического текста. Например: «Загрузка информации о погоде из службы weather.com завершилась неудачно: соединение не удалось», за которым следует трассировка стека.

Для консольных приложений, которые немедленно останавливаются, я предпочитаю видеть трассировку стека непосредственно на экране, как написано printStackTrace().

...