Obtener tamaño de carpeta o archivo


105

¿Cómo puedo recuperar el tamaño de la carpeta o el archivo en Java?



Si tienes Android , échale un vistazo StatFs. Utiliza estadísticas del sistema de archivos y es casi 1000 veces más rápido que los métodos recursivos, que no se podían utilizar para nuestras necesidades. Nuestra implementación se puede encontrar aquí: stackoverflow.com/a/58418639/293280
Joshua Pinter

Respuestas:


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

Esto devuelve la longitud del archivo en bytes o 0si el archivo no existe. No hay una forma incorporada de obtener el tamaño de una carpeta, tendrá que recorrer el árbol de directorios de forma recursiva (utilizando el listFiles()método de un objeto de archivo que representa un directorio) y acumular el tamaño del directorio por sí mismo:

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;
}

ADVERTENCIA : Este método no es lo suficientemente sólido para su uso en producción. directory.listFiles()puede volver nully causar un NullPointerException. Además, no considera enlaces simbólicos y posiblemente tenga otros modos de falla. Utilice este método .


11
Tenga cuidado si ejecuta esto en el directorio raíz C: en una máquina con Windows; hay un archivo de sistema que no es (según java.io.File) ni un archivo ni un directorio. Es posible que desee cambiar la cláusula else para comprobar que el archivo es en realidad un directorio.
Paul Clapham

2
Cambio simple para verificar el parámetro para ver si no es un directorio al comienzo del método y devolver la longitud, entonces la recursividad es más simple: simplemente agregue la llamada a sí mismo en el mismo método y luego esto admite pasar una referencia de archivo en su lugar de un directorio también.
Kevin Brock

3
Si usa Java 7 o superior, use la respuesta stackoverflow.com/a/19877372/40064 , es mucho más rápido.
Wim Deblauwe

1
Esto se confundirá con los enlaces simbólicos. Además, puede arrojar un NullPointerExceptionsi el directorio se modifica al mismo tiempo.
Aleksandr Dubinsky

43

Usando java-7 nio api, calcular el tamaño de la carpeta se puede hacer mucho más rápido.

Aquí hay un ejemplo listo para ejecutar que es robusto y no generará una excepción. Registrará los directorios en los que no puede ingresar o tuvo problemas para recorrer. Los enlaces simbólicos se ignoran y la modificación simultánea del directorio no causará más problemas de los necesarios.

/**
 * 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();
}

¿Existe un equivalente para esto en el desarrollo de Android?
desarrollador de Android

¿Hay alguna razón para usar en AtomicLonglugar de solo long?
Lukas Schmelzeisen

La variable tiene que ser definitiva cuando se accede desde una clase anónima
Aksel Willgert

1
Hice una evaluación comparativa con JMH y este método de API de NIO es aproximadamente de 4 a 5 veces más rápido en comparación con el código commons-io (probado en una carpeta con muchas subcarpetas para un total de 180229 archivos). Commons IO tomó 15 segundos, NIO tomó 5 segundos.
Wim Deblauwe

3
Este enfoque es el más sólido. Se ocupa de enlaces simbólicos, modificaciones simultáneas, excepciones de seguridad, funciona tanto con archivos como con directorios, etc. ¡Es una lástima Filesque no lo admita directamente!
Aleksandr Dubinsky

38

Necesitas FileUtils#sizeOfDirectory(File)de commons-io .

Tenga en cuenta que deberá verificar manualmente si el archivo es un directorio, ya que el método genera una excepción si se le pasa un no directorio.

ADVERTENCIA : Este método (a partir de commons-io 2.4) tiene un error y puede producirse IllegalArgumentExceptionsi el directorio se modifica al mismo tiempo.


Entonces, ¿qué sucede cuando el archivo no es un directorio? cuando no existe? etc - qué horribles documentos
Mr_and_Mrs_D

@Mr_and_Mrs_D - Simplemente copie y pegue las líneas después del checkDirectory(directory);cheque. Solo asegúrate de que File.listFilestenga hijos. Refs: FileUtils.sizeOfDirectory () , File.listFiles ()
Mr. Polywhirl

3
Consulte el error IO-449 . Este método arrojará un IllegalArgumentExceptionsi el directorio se modifica mientras está iterando.
Aleksandr Dubinsky

¡¡¡Ay!!! Eso apesta ... sí, enumera archivos y luego, si uno se elimina mientras el código se está ejecutando, arroja.
Dean Hiller

19

En Java 8:

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

Sería mejor usarlo Files::sizeen el paso del mapa, pero arroja una excepción marcada.

ACTUALIZACIÓN:
también debe tener en cuenta que esto puede generar una excepción si no se puede acceder a algunos de los archivos / carpetas. Vea esta pregunta y otra solución usando Guava .


1
Estaba buscando algo similar y terminé con el código en cuestión: stackoverflow.com/questions/22867286/… , como puede ver, hay otro aspecto del manejo de errores que también causa problemas.
Aksel Willgert

@AkselWillgert Gracias, esto es lamentable y he actualizado la respuesta. Ahora cambiando a 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, su código debe tener una solución simple, en la llamada recursiva, debe agregar el tamaño al tamaño existente, no solo asignarlo. size += getFolderSize(file);
Teja Kantamneni

@Teja: Gracias por señalarlo, pero los cambios también estarán en la declaración if
Vishal

A veces, en una carpeta en crecimiento (otro hilo está descargando archivos y carpetas y, al mismo tiempo, estoy imprimiendo el tamaño de la carpeta a medida que avanza) da nullpointerexception en la línea "para (File file: dir.listFiles ()) {". Algunos archivos aparecen y desaparecen rápidamente en una carpeta activa. Así que agregué una verificación nula para el valor de retorno dir.listFiles () antes del ciclo.
csonuryilmaz

De File.listFiles () javadoc: "La matriz estará vacía si el directorio está vacío. Devuelve nulo si este nombre de ruta abstracto no denota un directorio, o si ocurre un error de E / S". Entonces, el comentario anterior es útil cuando se obtiene el tamaño de la carpeta en carpetas que cambian dinámicamente.
csonuryilmaz

7

Para Java 8, esta es una forma correcta de hacerlo:

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

Es importante filtrar todos los directorios , porque no se garantiza que el método de longitud sea 0 para los directorios.

Al menos este código ofrece la misma información de tamaño que el propio Explorador de Windows.


4

Esta es la mejor manera de obtener el tamaño de un archivo general (funciona para directorio y no directorio):

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;
}

Editar: tenga en cuenta que probablemente esta operación llevará mucho tiempo. No lo ejecutes en el hilo de la interfaz de usuario.

Además, aquí (tomado de https://stackoverflow.com/a/5599842/1696171 ) hay una buena manera de obtener una cadena legible por el usuario de la devolución larga:

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

Si desea utilizar Java 8 NIO API, el siguiente programa imprimirá el tamaño, en bytes, del directorio en el que se encuentra.

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;
        }
    }

}

El calculateSizemétodo es universal para Pathobjetos, por lo que también funciona para archivos. Tenga en cuenta que si un archivo o directorio es inaccesible, en este caso, el tamaño devuelto del objeto de ruta será 0.


3

File.length()( Javadoc ).

Tenga en cuenta que esto no funciona para directorios o no se garantiza que funcione.

Para un directorio, ¿qué quieres? Si es el tamaño total de todos los archivos debajo de él, puede caminar recursivamente a los niños usando File.list()y File.isDirectory()y sumar sus tamaños.


3

El Fileobjeto tiene un lengthmétodo:

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

3
  • Funciona para Android y Java
  • Funciona tanto para carpetas como para archivos
  • Comprueba si hay puntero nulo en todas partes donde sea necesario
  • Ignora el enlace simbólico también conocido como atajos
  • ¡Producción lista!

Código fuente:

   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

para Windows, usando java.io esta función reccursiva es útil.

    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;
}

Esto está probado y funciona correctamente por mi parte.


1

He probado du -c <folderpath>y es 2 veces más rápido que nio.Files o recursividad

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

Después de mucha investigación y análisis de las diferentes soluciones propuestas aquí en StackOverflow. Finalmente decidí escribir mi propia solución. Mi propósito es tener un mecanismo de no tirar porque no quiero fallar si la API no puede recuperar el tamaño de la carpeta. Este método no es adecuado para escenarios de subprocesos múltiples.

En primer lugar, quiero comprobar los directorios válidos mientras recorro el árbol del sistema de archivos.

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

En segundo lugar, no quiero que mi llamada recursiva entre en enlaces simbólicos (enlaces suaves) e incluya el tamaño en total agregado.

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());
}

Finalmente, mi implementación basada en recursividad para obtener el tamaño del directorio especificado. Observe la comprobación nula de dir.listFiles (). Según javadoc, existe la posibilidad de que este método pueda devolver un valor nulo.

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;
    }
}

Un poco de crema en el pastel, la API para obtener el tamaño de los archivos de la lista (pueden ser todos los archivos y carpetas en la raíz).

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

en linux si desea ordenar directorios entonces du -hs * | sort -h


0

Puede utilizar Apache Commons IOpara encontrar el tamaño de la carpeta fácilmente.

Si está en maven, agregue la siguiente dependencia en su pom.xmlarchivo.

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

Si no eres fanático de Maven, descarga el siguiente jar y agrégalo a la ruta de clases.

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
}

Para obtener el tamaño del archivo a través de Commons IO,

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

long fileSize = FileUtils.sizeOf(file);

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

También se puede lograr a través de Google Guava

Para Maven, agregue lo siguiente:

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

Si no usa Maven, agregue lo siguiente a la ruta de clases

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;
    }

Para obtener el tamaño del archivo,

 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;
        }

Aunque su código se ve bien, no estoy seguro de que agregue nada a las otras respuestas. Si es así, edite su respuesta para explicarlo.
Dragon Thoughts

Es solo una versión actualizada de hacer el mismo trabajo en menos líneas de código.
Jaskaran Singh
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.