In che modo "Prova-risorse" funzionano effettivamente nel contesto di questo programma che elimina tutti i file e le cartelle sotto un determinato nodo di directory

StackOverflow https://stackoverflow.com//questions/22056960

Domanda

Questo programma elimina tutti i file e le cartelle sotto un determinato nodo.

* Modifica *

Ho il seguente "Test" Struttura della directory sull'unità K:

Folder K:\garbage\
f_00000b (file)
f_00000f ( " )
f_0000b3 ( " )
dir1    [FOLDER]

Folder K:\garbage\dir1\
abc.pdf (file)
b12.pdf (file)
b36.pdf (file)
dir2   [FOLDER]

Folder K:\garbage\dir1\dir2\
A.pdf   (file)
a1.pdf  (file)
A2.pdf  (file)
.

* End Edit *

Programma funziona perché sono inciampato su "Try-with-Resources", la linea circondata da tutti i / / //////////////////////////////////// Essere " la risorsa ".

import java.io.IOError;
import java.io.IOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.NotDirectoryException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import javax.swing.JOptionPane;

public class CreatingDirectories {

    public static void main(String[] args) {

      deleteEverythingBelowThisNode(Paths.get("K:/garbage/dir1/dir2"));
    }

    static void deleteAllFilesIn(String ps){

      Path p = Paths.get(ps);

      try ////////////////////////////////////////////////////////////////
         (DirectoryStream<Path> paths = Files.newDirectoryStream(p)) /////
      { //////////////////////////////////////////////////////////////////

        for(Path q: paths)
          Files.delete(q);

      }catch(NotDirectoryException e){
        System.out.println("Not directory: " + p.toString() + "--" + e);
      }catch(DirectoryNotEmptyException e){
        System.out.println("Not empty: " + p.toString() + "--" + e);
      }
      catch(IOException e){
        System.out.println("IO: " + p.toString() + "--" + e);
      }
      catch(IOError e){
        System.out.println("IO ERROR: " + e);
      }
    }

    static void deleteEverythingBelowThisNode(Path p){

      String            sep        = p.getFileSystem().getSeparator();
      ArrayList<String> pathPieces = new ArrayList<>() ;
      String []         paths      = new String[p.getNameCount()];

      for(int i = 0 ; i < p.getNameCount() ; i++){
        pathPieces.add(p.getName(i).toString());
        paths[i] = p.getRoot().toString();
      }

      for(int i = 0; i < p.getNameCount() ; i++)
        for(int k = 0; k <= i; k++)
          paths[i] += pathPieces.get(k) + sep;

      for(int k = p.getNameCount() - 1; k >= 0; k--)
        deleteAllFilesIn(paths[k]);
    }
}
.

Capisco che "prova con risorse" è necessario: il programma funziona con esso, non senza di esso.

Ma non capisco perché e non so come ha risolto il problema originale, che ora descrivo.

I originariamente avevo situato le "risorse" sopra il tentativo, come questo, che sembra perfettamente naturale:

      DirectoryStream<Path> paths = Files.newDirectoryStream(p);
      try {
           for...
.

Con la struttura del programma altrimenti identica ad eccezione di spostamento che una linea come mostrato sopra, tutti i file e la sottocartella erano stati cancellati con successo da una cartella, ma è stato lanciato DirectoryNotEmptyException. Esplora di Windows ha confermato che la directory è stata vuota dopo il programma terminato a causa dell'eccezione.

Perché l'eccezione è stata gettata su una directory vuota?

Da la bocca del cavallo , "il tentativo Dichiarazione -resources ... dichiara ... Un oggetto che ... è chiuso alla fine della dichiarazione. "

La chiusura avviene alla fine della dichiarazione, quindi alla fine del ciclo. In che modo l'eccezione non è avvenuta anche con prove con risorse?

Come ora è, dopo aver looping attraverso l'intero nodo, tutto sotto di esso è stato cancellato.

Allora, cosa faceva effettivamente provare le risorse per abilitare la cancellazione di una cartella vuota che non può essere cancellata senza provare risorse?

Questi non sembrano domande stupide o una situazione banale.

Un generatodicetagcode si verifica in realtà comunque, ma provare in qualche modo le risorse? Non posso credere che lo sto chiedendo, dal momento che sembra una domanda stupida, ma ciò che è stato effettivamente accaduto per far funzionare il programma come previsto?

È stato utile?

Soluzione

Su Windows, non è possibile eliminare un file o una directory che è ancora aperta. (Su UNIX, d'altra parte, questo non è un problema: il file verrà eliminato dalla struttura della directory quando lo elimini e dal disco quando lo chiudi. Ma questo è su Unix.)

Quindi se non si utilizza l'istruzione Try-with-Resources per chiudere il flusso di directory, avrai comunque sottodirectory aperto al momento in cui si tenta di eliminare i file nella directory principale e che tenta alla sottodirectory Questo è ancora aperto fallirà. Dal momento che ignori le eccezioni (le stai semplicemente stampando), il tentativo successivo di eliminare la directory principale non riuscirà anche con un DirectoryNotEmptyException poiché non è stato eliminato tutte le sottodirectory.

Puoi verificare se questo è davvero il caso. Quando si esegue non utilizzano risorse try-with, assicurati di chiudere esplicitamente il flusso di directory dopo aver eliminato tutti i file nella directory (usando paths.close();)

che dovrebbe avere lo stesso effetto del blocco tentativo di risorse (a meno che non si verifichi un'eccezione - garantire esattamente lo stesso comportamento del try-with-risorse, è necessario inserire paths.close(); in un blocco finally).

Altri suggerimenti

Erwin spiega la tua domanda, ma hai anche un problema abbastanza serio alla fine del tuo elenco, a:

   for(int k = p.getNameCount() - 1; k >= 0; k--)
        deleteAllFilesIn(paths[k]);
.

Si crea un elenco di parti del percorso, quindi, ad esempio, le parti ci saranno:

    .
  • K: / Garbage / Dir1 / Dir2
  • k: / Garbage / dir1
  • k: / Garbage
  • k: /

significa che alla fine cercherai di eliminare tutto in K:.Proverà a eliminare tutto a K: \ (tutti i file; fallirà in generale se ci sono sottodirectory non vuoti).

Supponendo che tu voglia solo eliminare i file di livello più basso, probabilmente si desidera modificare la funzione deleteEverythingBelowThisNode().

(Spero che sia OK per "rispondere alla mia domanda" per rendere la "linea di fondo" del thread mostra ciò che funzionava il lavoro. In questo modo chiunque abbia il thread non dovrà sembrare difficile per la soluzione.)

Comunque, ecco deleteAllFilesBelowThisNode con il suggerimento di @ Erwin.

static void deleteAllFilesBelowThisNode(String ps) throws IOException{

  Path p = Paths.get(ps);

  try
  {
    paths = Files.newDirectoryStream(p);

    for(Path q: paths){

      if(JOptionPane.showConfirmDialog(null,"Deleting " + q.toString(),"",
           JOptionPane.OK_CANCEL_OPTION) 
        != JOptionPane.OK_OPTION)
                                  System.exit(9);

      Files.delete(q);
      System.out.println(q.toString() + " deleted");
    }
  }
  finally{
    JOptionPane.showMessageDialog(null,"AHA!");
    paths.close();
  }
}
.

Ho aggiunto il "AHA!" Perché finalmente ho capito cosa sta succedendo.

* Modifica *

E ho tirato fuori tutto ciò che ho aggiunto con orgoglio ieri perché ancora una volta mi trovo come denso come mercurio. Il pianeta, il metallo, l'auto ... whatevvvvvvvvvvs.

Avevo dimenticato che c'erano tre chiamate separate al DeleteAllFilesBelowThisNode, che ha davvero confuso il diavolo da me. Diamine, è il mio programma Dang, ma ... Foresta per gli alberi, e tutto questo. Non incluso l'intero programma, mi ha ingannato. Mi ha ingannato bene. Dern Buono.

Non sono davvero un idiota.

* End Edit

Ma ho lasciato questo:

Grazie, Erwin!

* un'altra modifica *

Ecco la produzione, per la comprensione:

Delete all entries beneath K:\garbage\dir1\dir2\
  deleting K:\garbage\dir1\dir2\A.pdf ... deleted
  deleting K:\garbage\dir1\dir2\a1 and 2 ver 2.pdf ... deleted
  deleting K:\garbage\dir1\dir2\A1 and 2.pdf ... deleted
K:\garbage\dir1\dir2\ closed by finally. ----- THUS DELETEABLE

Delete all entries beneath K:\garbage\dir1\
  deleting K:\garbage\dir1\abc.pdf ... deleted
  deleting K:\garbage\dir1\b12.pdf ... deleted
  deleting K:\garbage\dir1\b36.pdf ... deleted
  deleting K:\garbage\dir1\dir2 ... ***DELETED***
K:\garbage\dir1\ closed by finally. ----- THUS DELETEABLE


Delete all entries beneath K:\garbage\
  deleting K:\garbage\dir1 ... ***DELETED***
  deleting K:\garbage\f_00000b ... deleted
  deleting K:\garbage\f_00000f ... deleted
  deleting K:\garbage\f_0000b3 ... deleted
K:\garbage\ closed by finally.
.

Ecco l'intero programma:

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import javax.swing.JOptionPane;

public class CreatingDirectories {

  static void deleteAllFilesBelowThisNode(String ps) throws IOException{

    DirectoryStream<Path> paths = null;

    try
    {
      paths = Files.newDirectoryStream(Paths.get(ps));

      for(Path q: paths){
                         System.out.print("deleting " + q.toString() + " ... ");
        if(JOptionPane.showConfirmDialog(null,"Deleting " + q.toString(),"",
             JOptionPane.OK_CANCEL_OPTION) 
          != JOptionPane.OK_OPTION)
                                                               System.exit(9);
        Files.delete(q);
                                                  System.out.println("deleted");
      }
    }
    finally{  

      paths.close();         
      System.out.println("\n" + ps + " closed by finally.\n");
    }
  }

  static void iterativelyDeleteFoldersFromHereUpToRoot(Path p) throws IOException{

    String            sep        = p.getFileSystem().getSeparator();
    ArrayList<String> pathPieces = new ArrayList<>() ;
    String []         paths      = new String[p.getNameCount()];

    for(int i = 0 ; i < p.getNameCount() ; i++){

      pathPieces.add(p.getName(i).toString());

      paths[i] = p.getRoot().toString();
    }

    for(int i = 0; i < p.getNameCount() ; i++)
      for(int k = 0; k <= i; k++)
                                  paths[i] += pathPieces.get(k) + sep;

    for(int k = p.getNameCount() - 1; k >= 0; k--){

      System.out.println("\nDelete all entries beneath " + paths[k].toString());

      deleteAllFilesBelowThisNode(paths[k]);
    }
  }

  public static void main(String[] args) throws IOException {

    iterativelyDeleteFoldersFromHereUpToRoot(Paths.get("K:/garbage/dir1/dir2"));
  }
}
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top