Uzyskaj rozmiar folderu lub pliku


105

Jak mogę sprawdzić rozmiar folderu lub pliku w Javie?



Jeśli korzystasz z Androida, spójrz na StatFs. Korzysta ze statystyk systemu plików i jest prawie 1000x szybszy niż metody rekurencyjne, które były bezużyteczne dla naszych potrzeb. Naszą implementację można znaleźć tutaj: stackoverflow.com/a/58418639/293280
Joshua Pinter

Odpowiedzi:


191
java.io.File file = new java.io.File("myfile.txt");
file.length();

Zwraca długość pliku w bajtach lub 0jeśli plik nie istnieje. Nie ma wbudowanego sposobu, aby uzyskać rozmiar folderu, będziesz musiał chodzić po drzewie katalogów rekurencyjnie (używając listFiles()metody obiektu pliku, który reprezentuje katalog) i zgromadzić rozmiar katalogu dla siebie:

public static long folderSize(File directory) {
    long length = 0;
    for (File file : directory.listFiles()) {
        if (file.isFile())
            length += file.length();
        else
            length += folderSize(file);
    }
    return length;
}

OSTRZEŻENIE : Ta metoda nie jest wystarczająco solidna do użytku produkcyjnego. directory.listFiles()może powrócić nulli spowodować NullPointerException. Ponadto nie uwzględnia dowiązań symbolicznych i prawdopodobnie ma inne tryby awarii. Użyj tej metody .


11
Zachowaj ostrożność, jeśli uruchomisz to w katalogu głównym C: na komputerze z systemem Windows; jest tam plik systemowy, który (według java.io.File) nie jest ani plikiem, ani katalogiem. Możesz chcieć zmienić klauzulę else, aby sprawdzić, czy plik jest rzeczywiście katalogiem.
Paul Clapham

2
Prosta zmiana, aby sprawdzić parametr, aby zobaczyć, czy nie jest to katalog na początku metody i zwrócić długość, wówczas rekursja jest prostsza - wystarczy dodać wywołanie do self w tej samej metodzie, a zamiast tego obsługuje przekazanie odwołania do pliku katalogu.
Kevin Brock

3
Jeśli używasz języka Java 7 lub nowszego, użyj odpowiedzi stackoverflow.com/a/19877372/40064 , jest to znacznie szybsze.
Wim Deblauwe

1
Zostanie to zdezorientowane przez linki symboliczne. Może również wyrzucić a, NullPointerExceptionjeśli katalog jest jednocześnie modyfikowany.
Aleksandr Dubinsky

43

Korzystając z interfejsu API java-7 nio, obliczanie rozmiaru folderu może być wykonane znacznie szybciej.

Oto gotowy do uruchomienia przykład, który jest solidny i nie zgłosi wyjątku. Będzie rejestrować katalogi, do których nie może wejść lub miał problemy z przechodzeniem. Dowiązania symboliczne są ignorowane, a jednoczesna modyfikacja katalogu nie sprawi więcej kłopotów niż to konieczne.

/**
 * Attempts to calculate the size of a file or directory.
 * 
 * <p>
 * Since the operation is non-atomic, the returned value may be inaccurate.
 * However, this method is quick and does its best.
 */
public static long size(Path path) {

    final AtomicLong size = new AtomicLong(0);

    try {
        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {

                size.addAndGet(attrs.size());
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) {

                System.out.println("skipped: " + file + " (" + exc + ")");
                // Skip folders that can't be traversed
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) {

                if (exc != null)
                    System.out.println("had trouble traversing: " + dir + " (" + exc + ")");
                // Ignore errors traversing a folder
                return FileVisitResult.CONTINUE;
            }
        });
    } catch (IOException e) {
        throw new AssertionError("walkFileTree will not throw IOException if the FileVisitor does not");
    }

    return size.get();
}

Czy istnieje odpowiednik tego w programowaniu na Androida?
programista Androida

Czy jest powód do używania AtomicLongzamiast tylko long?
Lukas Schmelzeisen

Zmienna musi być ostateczna, gdy jest dostępna z anonimowej klasy
Aksel Willgert,

1
Zrobiłem test porównawczy przy użyciu JMH i ta metoda NIO api jest około 4 do 5 razy szybsza w porównaniu z kodem commons-io (testowany na folderze z wieloma podfolderami dla łącznie 180229 plików). Commons IO zajęło 15 sekund, NIO 5 sekund.
Wim Deblauwe

3
To podejście jest najsolidniejsze. Zajmuje się dowiązaniami symbolicznymi, równoczesną modyfikacją, wyjątkami bezpieczeństwa, współpracuje zarówno z plikami, jak i katalogami itp. Szkoda, Filesże nie obsługuje go bezpośrednio!
Aleksandr Dubinsky

38

Potrzebujesz FileUtils#sizeOfDirectory(File)od commons-io .

Zauważ, że będziesz musiał ręcznie sprawdzić, czy plik jest katalogiem, ponieważ metoda zgłasza wyjątek, jeśli przekazano do niego plik niebędący katalogiem.

OSTRZEŻENIE : Ta metoda (od commons-io 2.4) ma błąd i może zgłosić, IllegalArgumentExceptionjeśli katalog jest jednocześnie modyfikowany.


Więc co się dzieje, gdy plik nie jest katalogiem? kiedy nie istnieje? etc - howful docs
Mr_and_Mrs_D

@Mr_and_Mrs_D - Po prostu skopiuj i wklej linie po checkDirectory(directory);sprawdzeniu. Tylko upewnij się, że File.listFilesma dzieci. Odniesienia: FileUtils.sizeOfDirectory () , File.listFiles ()
Pan Polywhirl,

3
Zobacz błąd IO-449 . Ta metoda zgłosi, IllegalArgumentExceptionjeśli katalog zostanie zmodyfikowany podczas iteracji.
Aleksandr Dubinsky

Auć!!! To jest do bani ... tak, wyświetla listę plików, a jeśli jeden z nich zostanie usunięty podczas działania kodu, wyrzuca.
Dean Hiller

19

W Javie 8:

long size = Files.walk(path).mapToLong( p -> p.toFile().length() ).sum();

Byłoby przyjemniejsze w użyciu Files::sizew kroku mapy, ale zgłasza zaznaczony wyjątek.

UPDATE:
Należy również pamiętać, że może to spowodować wyjątek, jeśli niektóre pliki / foldery nie są dostępne. Zobacz to pytanie i inne rozwiązanie z użyciem guawy .


1
Szukałem czegoś podobnego i skończyło się na tym kodzie: stackoverflow.com/questions/22867286/… , jak widzisz, jest inny aspekt obsługi błędów, który również powoduje problemy.
Aksel Willgert

@AkselWillgert Dzięki, to niefortunne i zaktualizowałem odpowiedź. Teraz przechodzę na stos Guava stackoverflow.com/a/24757556/1180621
Andrejs

10
public static long getFolderSize(File dir) {
    long size = 0;
    for (File file : dir.listFiles()) {
        if (file.isFile()) {
            System.out.println(file.getName() + " " + file.length());
            size += file.length();
        }
        else
            size += getFolderSize(file);
    }
    return size;
}

1
@Vishal Twój kod musi mieć prostą poprawkę, w wywołaniu rekurencyjnym powinieneś dodać rozmiar do istniejącego rozmiaru, a nie tylko go przypisać. size += getFolderSize(file);
Teja Kantamneni

@Teja: Dzięki za zwrócenie uwagi, ale zmiany będą również w oświadczeniu if
Vishal

Czasami w rosnącym folderze (inny wątek pobiera pliki i foldery, a jednocześnie drukuję rozmiar folderu w miarę postępu) daje to zerowy wyjątek w wierszu "for (File file: dir.listFiles ()) {". Niektóre pliki pojawiają się i szybko znikają w aktywnym folderze. Więc dodałem zerową kontrolę dla wartości zwracanej przez dir.listFiles () przed pętlą for.
csonuryilmaz

From File.listFiles () javadoc: "Tablica będzie pusta, jeśli katalog jest pusty. Zwraca wartość null, jeśli ta abstrakcyjna nazwa ścieżki nie oznacza katalogu lub jeśli wystąpi błąd we / wy." Tak więc powyższy komentarz jest przydatny podczas pobierania rozmiaru folderu w dynamicznie zmieniających się folderach.
csonuryilmaz

7

W przypadku Java 8 jest to właściwy sposób:

Files.walk(new File("D:/temp").toPath())
                .map(f -> f.toFile())
                .filter(f -> f.isFile())
                .mapToLong(f -> f.length()).sum()

Odfiltrowanie wszystkich katalogów jest ważne , ponieważ metoda length nie gwarantuje wartości 0 dla katalogów.

Przynajmniej ten kod dostarcza takich samych informacji o rozmiarze, jak sam Eksplorator Windows.


4

Oto najlepszy sposób na uzyskanie ogólnego rozmiaru pliku (działa w przypadku katalogu i niekatalogu):

public static long getSize(File file) {
    long size;
    if (file.isDirectory()) {
        size = 0;
        for (File child : file.listFiles()) {
            size += getSize(child);
        }
    } else {
        size = file.length();
    }
    return size;
}

Edycja: Zauważ, że będzie to prawdopodobnie czasochłonna operacja. Nie uruchamiaj go w wątku interfejsu użytkownika.

Również tutaj (pobrane z https://stackoverflow.com/a/5599842/1696171 ) jest dobrym sposobem na uzyskanie czytelnego dla użytkownika ciągu z długo zwróconego:

public static String getReadableSize(long size) {
    if(size <= 0) return "0";
    final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
    int digitGroups = (int) (Math.log10(size)/Math.log10(1024));
    return new DecimalFormat("#,##0.#").format(size/Math.pow(1024, digitGroups))
            + " " + units[digitGroups];
}

4

Jeśli chcesz używać Java 8 NIO API, następujący program wydrukuje rozmiar katalogu, w którym się znajduje, w bajtach.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class PathSize {

    public static void main(String[] args) {
        Path path = Paths.get(".");
        long size = calculateSize(path);
        System.out.println(size);
    }

    /**
     * Returns the size, in bytes, of the specified <tt>path</tt>. If the given
     * path is a regular file, trivially its size is returned. Else the path is
     * a directory and its contents are recursively explored, returning the
     * total sum of all files within the directory.
     * <p>
     * If an I/O exception occurs, it is suppressed within this method and
     * <tt>0</tt> is returned as the size of the specified <tt>path</tt>.
     * 
     * @param path path whose size is to be returned
     * @return size of the specified path
     */
    public static long calculateSize(Path path) {
        try {
            if (Files.isRegularFile(path)) {
                return Files.size(path);
            }

            return Files.list(path).mapToLong(PathSize::calculateSize).sum();
        } catch (IOException e) {
            return 0L;
        }
    }

}

calculateSizeMetoda jest uniwersalna dla Pathobiektów, więc to działa również dla plików. Zauważ, że jeśli plik lub katalog jest niedostępny, w tym przypadku zwracany rozmiar obiektu ścieżki będzie 0.


3

File.length()( Javadoc ).

Zauważ, że to nie działa w przypadku katalogów lub nie ma gwarancji, że zadziała.

Czego chcesz w przypadku katalogu? Jeśli jest to całkowity rozmiar wszystkich plików znajdujących się pod nim, możesz rekurencyjnie spacerować dzieci używając File.list()i File.isDirectory()i zsumować ich rozmiary.


3

FileObiekt ma lengthmetodę:

f = new File("your/file/name");
f.length();

3
  • Działa na Androida i Java
  • Działa zarówno dla folderów, jak i plików
  • Sprawdza wskaźnik zerowy wszędzie tam, gdzie jest to potrzebne
  • Ignoruje dowiązania symboliczne, czyli skróty
  • Produkcja gotowa!

Kod źródłowy:

   public long fileSize(File root) {
        if(root == null){
            return 0;
        }
        if(root.isFile()){
            return root.length();
        }
        try {
            if(isSymlink(root)){
                return 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return 0;
        }

        long length = 0;
        File[] files = root.listFiles();
        if(files == null){
            return 0;
        }
        for (File file : files) {
            length += fileSize(file);
        }

        return length;
    }

    private static boolean isSymlink(File file) throws IOException {
        File canon;
        if (file.getParent() == null) {
            canon = file;
        } else {
            File canonDir = file.getParentFile().getCanonicalFile();
            canon = new File(canonDir, file.getName());
        }
        return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
    }

1

dla Windows, używając java.io, ta rekurencyjna funkcja jest przydatna.

    public static long folderSize(File directory) {
    long length = 0;

    if (directory.isFile())
         length += directory.length();
    else{
        for (File file : directory.listFiles()) {
             if (file.isFile())
                 length += file.length();
             else
                 length += folderSize(file);
        }
    }

    return length;
}

To jest przetestowane i działa poprawnie po mojej stronie.


1

Przetestowałem du -c <folderpath>i jest 2x szybszy niż nio.Files lub rekurencja

private static long getFolderSize(File folder){
  if (folder != null && folder.exists() && folder.canRead()){
    try {
      Process p = new ProcessBuilder("du","-c",folder.getAbsolutePath()).start();
      BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
      String total = "";
      for (String line; null != (line = r.readLine());)
        total = line;
      r.close();
      p.waitFor();
      if (total.length() > 0 && total.endsWith("total"))
        return Long.parseLong(total.split("\\s+")[0]) * 1024;
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
  return -1;
}

0
public long folderSize (String directory)
    {
        File curDir = new File(directory);
        long length = 0;
        for(File f : curDir.listFiles())
        {
            if(f.isDirectory())
            {               
                 for ( File child : f.listFiles()) 
                 {
                     length = length + child.length();
                 }

                System.out.println("Directory: " + f.getName() + " " + length + "kb");
            }
            else
            {
                length = f.length();
                System.out.println("File: " + f.getName() + " " + length + "kb");
            }
            length = 0;
        }
        return length;
    }

0

Po wielu badaniach i przyjrzeniu się różnym rozwiązaniom zaproponowanym tutaj w StackOverflow. W końcu zdecydowałem się napisać własne rozwiązanie. Moim celem jest posiadanie mechanizmu no-throw, ponieważ nie chcę się zawiesić, jeśli interfejs API nie może pobrać rozmiaru folderu. Ta metoda nie jest odpowiednia w przypadku scenariusza wielowątkowego.

Przede wszystkim chcę sprawdzić poprawne katalogi podczas przeglądania drzewa systemu plików.

private static boolean isValidDir(File dir){
    if (dir != null && dir.exists() && dir.isDirectory()){
        return true;
    }else{
        return false;
    }
}

Po drugie, nie chcę, aby moje wywołanie rekurencyjne przechodziło do dowiązań symbolicznych (miękkich) i zawierało łączną wielkość.

public static boolean isSymlink(File file) throws IOException {
    File canon;
    if (file.getParent() == null) {
        canon = file;
    } else {
        canon = new File(file.getParentFile().getCanonicalFile(),
                file.getName());
    }
    return !canon.getCanonicalFile().equals(canon.getAbsoluteFile());
}

Wreszcie moja implementacja oparta na rekurencji, aby pobrać rozmiar określonego katalogu. Zwróć uwagę na zerowe sprawdzenie dla dir.listFiles (). Według javadoc istnieje możliwość, że ta metoda może zwrócić wartość null.

public static long getDirSize(File dir){
    if (!isValidDir(dir))
        return 0L;
    File[] files = dir.listFiles();
    //Guard for null pointer exception on files
    if (files == null){
        return 0L;
    }else{
        long size = 0L;
        for(File file : files){
            if (file.isFile()){
                size += file.length();
            }else{
                try{
                    if (!isSymlink(file)) size += getDirSize(file);
                }catch (IOException ioe){
                    //digest exception
                }
            }
        }
        return size;
    }
}

Trochę kremu na torcie, API, aby uzyskać rozmiar listy plików (może to być wszystkie pliki i foldery w katalogu głównym).

public static long getDirSize(List<File> files){
    long size = 0L;
    for(File file : files){
        if (file.isDirectory()){
            size += getDirSize(file);
        } else {
            size += file.length();
        }
    }
    return size;
}

0

w Linuksie, jeśli chcesz sortować katalogi, to du -hs * | sort -h


0

Możesz użyć, Apache Commons IOaby łatwo znaleźć rozmiar folderu.

Jeśli jesteś na maven, dodaj następującą zależność w swoim pom.xmlpliku.

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>

Jeśli nie jesteś fanem Mavena, pobierz następujący plik jar i dodaj go do ścieżki klasy.

https://repo1.maven.org/maven2/commons-io/commons-io/2.6/commons-io-2.6.jar

public long getFolderSize() {

    File folder = new File("src/test/resources");
    long size = FileUtils.sizeOfDirectory(folder);

    return size; // in bytes
}

Aby uzyskać rozmiar pliku za pośrednictwem Commons IO,

File file = new File("ADD YOUR PATH TO FILE");

long fileSize = FileUtils.sizeOf(file);

System.out.println(fileSize); // bytes

Można to również osiągnąć za pomocą Google Guava

W przypadku Mavena dodaj następujące informacje:

<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>28.1-jre</version>
</dependency>

Jeśli nie używasz Mavena, dodaj następujący kod do ścieżki klasy

https://repo1.maven.org/maven2/com/google/guava/guava/28.1-jre/guava-28.1-jre.jar

public long getFolderSizeViaGuava() {
        File folder = new File("src/test/resources");
        Iterable<File> files = Files.fileTreeTraverser()
                .breadthFirstTraversal(folder);
        long size = StreamSupport.stream(files.spliterator(), false)
                .filter(f -> f.isFile())
                .mapToLong(File::length).sum();

        return  size;
    }

Aby uzyskać rozmiar pliku,

 File file = new File("PATH TO YOUR FILE");
 long s  = file.length();
 System.out.println(s);

0
private static long getFolderSize(Path folder) {
        try {
            return Files.walk(folder)
                      .filter(p -> p.toFile().isFile())
                      .mapToLong(p -> p.toFile().length())
                      .sum();
        } catch (IOException e) {
            e.printStackTrace();
            return 0L;
        }

Chociaż twój kod wygląda dobrze, nie jestem pewien, czy dodaje cokolwiek do innych odpowiedzi. Jeśli tak, zmień swoją odpowiedź, aby wyjaśnić.
Dragonthoughts,

To tylko zaktualizowana wersja wykonywania tej samej pracy w mniejszej liczbie wierszy kodu.
Jaskaran Singh,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.