Obtenha o tamanho da pasta ou arquivo

105

Como posso recuperar o tamanho da pasta ou arquivo em Java?

uma vez
fonte
O mesmo, mas com foco na eficiência: stackoverflow.com/questions/116574/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Se você estiver no Android , dê uma olhada em StatFs. Ele usa estatísticas do sistema de arquivos e é quase 1000 vezes mais rápido do que os métodos recursivos, que eram inutilizáveis ​​para nossas necessidades. Nossa implementação pode ser encontrada aqui: stackoverflow.com/a/58418639/293280
Joshua Pinter

Respostas:

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

Isso retorna o comprimento do arquivo em bytes ou 0se o arquivo não existir. Não existe uma maneira embutida de obter o tamanho de uma pasta. Você terá que percorrer a árvore de diretórios recursivamente (usando o listFiles()método de um objeto de arquivo que representa um diretório) e acumular o tamanho do diretório para você:

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

AVISO : Este método não é suficientemente robusto para uso em produção. directory.listFiles()pode retornar nulle causar a NullPointerException. Além disso, não considera links simbólicos e possivelmente possui outros modos de falha. Use este método .

Tendayi Mawushe
fonte
11
Tenha cuidado se você executar isso no diretório raiz C: em uma máquina Windows; há um arquivo de sistema lá que (de acordo com java.io.File) não é um arquivo nem um diretório. Você pode querer alterar a cláusula else para verificar se o arquivo é realmente um diretório.
Paul Clapham
2
Mudança simples para verificar o parâmetro para ver se não é um diretório no início do método e retornar o comprimento, então a recursão é mais simples - basta adicionar a chamada a si mesmo no mesmo método e então isso suporta a passagem de uma referência de arquivo. de um diretório também.
Kevin Brock
3
Se você usa Java 7 ou superior, use a resposta stackoverflow.com/a/19877372/40064 , é muito mais rápido.
Wim Deblauwe,
1
Isso será confundido com links simbólicos. Além disso, pode lançar um NullPointerExceptionse o diretório for modificado simultaneamente.
Aleksandr Dubinsky
43

Usando java-7 nio api, calcular o tamanho da pasta pode ser feito muito mais rápido.

Aqui está um exemplo pronto para execução que é robusto e não lançará uma exceção. Ele registrará os diretórios nos quais não pode entrar ou teve problemas para atravessar. Os links simbólicos são ignorados e a modificação simultânea do diretório não causará mais problemas do que o necessário.

/**
 * 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();
}
Aksel Willgert
fonte
Existe um equivalente para isso no desenvolvimento Android?
desenvolvedor Android
Existe uma razão para usar em AtomicLongvez de apenas long?
Lukas Schmelzeisen
A variável deve ser final quando acessada de uma classe anônima
Aksel Willgert
1
Fiz um benchmark usando JMH e este método NIO api é cerca de 4 a 5 vezes mais rápido em comparação com o código commons-io (testado em uma pasta com muitas subpastas para um total de 180229 arquivos). Commons IO levou 15 segundos, NIO levou 5 segundos.
Wim Deblauwe
3
Essa abordagem é a mais robusta. Ele lida com links simbólicos, modificação simultânea, exceções de segurança, funciona com arquivos e diretórios, etc. É uma pena Filesnão ter suporte direto!
Aleksandr Dubinsky,
38

Você precisa FileUtils#sizeOfDirectory(File)do commons-io .

Observe que você precisará verificar manualmente se o arquivo é um diretório, pois o método lança uma exceção se um não diretório for passado para ele.

AVISO : Este método (a partir de commons-io 2.4) tem um bug e pode lançar IllegalArgumentExceptionse o diretório for modificado simultaneamente.

Yegor256
fonte
Então, o que acontece quando o arquivo não é um diretório? quando não existe? etc - que documentos horríveis
Mr_and_Mrs_D
@Mr_and_Mrs_D - Basta copiar e colar as linhas após a checkDirectory(directory);verificação. Apenas certifique-se de que File.listFilestem filhos. Refs: FileUtils.sizeOfDirectory () , File.listFiles ()
Sr. Polywhirl
3
Veja bug IO-449 . Este método lançará um IllegalArgumentExceptionse o diretório for modificado durante a iteração.
Aleksandr Dubinsky
ai !!! Isso é péssimo ... sim, ele lista arquivos e, se um for excluído enquanto o código está sendo executado, ele joga.
Dean Hiller
19

Em Java 8:

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

Seria mais agradável usar Files::sizena etapa do mapa, mas lança uma exceção verificada.

ATUALIZAÇÃO:
Você também deve estar ciente de que isso pode lançar uma exceção se alguns dos arquivos / pastas não estiverem acessíveis. Veja esta pergunta e outra solução usando Guava .

Andrejs
fonte
1
eu estava procurando algo semelhante e acabei com o código em questão: stackoverflow.com/questions/22867286/… , como você pode ver, há outro aspecto do tratamento de erros que também causa problemas.
Aksel Willgert de
@AkselWillgert Obrigado, é lamentável e atualizei a resposta. Agora mudando para 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;
}
Vishal
fonte
1
@Vishal seu código precisa ter uma correção simples, na chamada recursiva, você deve adicionar o tamanho ao tamanho existente e não apenas atribuir a ele. size += getFolderSize(file);
Teja Kantamneni
@Teja: Obrigado por apontar, mas as mudanças estarão na declaração if também
Vishal
Às vezes, em uma pasta crescente (outro thread está baixando arquivos e pastas e ao mesmo tempo estou imprimindo o tamanho da pasta conforme o progresso), dá nullpointerexception na linha "for (file file: dir.listFiles ()) {". Alguns arquivos aparecem e desaparecem rapidamente em uma pasta viva. Portanto, adicionei uma verificação nula para o valor de retorno dir.listFiles () antes do loop for.
csonuryilmaz
De File.listFiles () javadoc: "O array estará vazio se o diretório estiver vazio. Retorna nulo se este nome de caminho abstrato não denota um diretório, ou se ocorrer um erro de E / S." Portanto, o comentário acima é útil ao obter o tamanho da pasta em pastas que mudam dinamicamente.
csonuryilmaz
7

Para Java 8, esta é uma maneira certa de fazer isso:

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

É importante filtrar todos os diretórios , porque o método de comprimento não tem garantia de ser 0 para diretórios.

Pelo menos esse código fornece as mesmas informações de tamanho que o próprio Windows Explorer.

wumpz
fonte
4

Esta é a melhor maneira de obter um tamanho de arquivo geral (funciona para diretório e não diretório):

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

Edit: Observe que esta provavelmente vai ser uma operação demorada. Não o execute no thread de interface do usuário.

Além disso, aqui (retirado de https://stackoverflow.com/a/5599842/1696171 ) está uma boa maneira de obter uma string legível pelo usuário a partir do longo retornado:

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];
}
Eric Cochran
fonte
4

Se você quiser usar a API Java 8 NIO , o programa a seguir imprimirá o tamanho, em bytes, do diretório em que está localizado.

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

}

O calculateSizemétodo é universal para Pathobjetos, por isso também funciona para arquivos. Observe que se um arquivo ou diretório estiver inacessível, neste caso o tamanho retornado do objeto de caminho será 0.

dinomario10
fonte
3

File.length()( Javadoc ).

Observe que isso não funciona para diretórios ou não é garantido que funcione.

Para um diretório, o que você deseja? Se é o tamanho total de todos os arquivos debaixo dela, você pode recursivamente anda crianças usando File.list()e File.isDirectory()e somar seus tamanhos.

danben
fonte
3

O Fileobjeto tem um lengthmétodo:

f = new File("your/file/name");
f.length();
JesperE
fonte
3
  • Funciona para Android e Java
  • Funciona para pastas e arquivos
  • Verifica se há ponteiro nulo em todos os lugares onde necessário
  • Ignora link simbólico também conhecido como atalhos
  • Produção pronta!

Código fonte:

   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());
    }
Ilya Gazman
fonte
1

para Windows, usando java.io, essa função recursiva é ú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;
}

Isso foi testado e está funcionando corretamente no meu lado.

É PD
fonte
1

Eu testei du -c <folderpath>e é 2x mais rápido que o nio.Arquivos ou recursão

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;
}
G Dias
fonte
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;
    }
Nicholas
fonte
0

Depois de muita pesquisa e análise de diferentes soluções propostas aqui no StackOverflow. Finalmente decidi escrever minha própria solução. Meu objetivo é ter um mecanismo de exclusão, porque não quero travar se a API não conseguir obter o tamanho da pasta. Este método não é adequado para cenário multithread.

Em primeiro lugar, quero verificar os diretórios válidos ao percorrer a árvore do sistema de arquivos.

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

Em segundo lugar, não quero que minha chamada recursiva entre em links simbólicos (softlinks) e inclua o tamanho no 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, minha implementação baseada em recursão para buscar o tamanho do diretório especificado. Observe a verificação de nulo para dir.listFiles (). De acordo com o javadoc, existe a possibilidade de esse método retornar 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;
    }
}

Um pouco de creme sobre o bolo, a API para obter o tamanho dos arquivos da lista (pode ser todos os arquivos e pastas na raiz).

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;
}
AB
fonte
0

no linux se você deseja ordenar os diretórios então du -hs * | sort -h

Prem S
fonte
0

Você pode usar Apache Commons IOpara encontrar o tamanho da pasta facilmente.

Se você estiver no maven, adicione a seguinte dependência em seu pom.xmlarquivo.

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

Se você não for fã do Maven, baixe o jar a seguir e adicione-o ao caminho da classe.

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 obter o tamanho do arquivo via Commons IO,

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

long fileSize = FileUtils.sizeOf(file);

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

Também é possível através de Google Guava

Para Maven, adicione o seguinte:

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

Se não estiver usando o Maven, adicione o seguinte ao caminho da classe

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 obter o tamanho do arquivo,

 File file = new File("PATH TO YOUR FILE");
 long s  = file.length();
 System.out.println(s);
Dulith De Costa
fonte
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;
        }
Jaskaran Singh
fonte
Embora seu código pareça bom, não tenho certeza se ele adiciona algo às outras respostas. Em caso afirmativo, edite sua resposta para explicar.
Dragonthoughts
É apenas uma versão atualizada de fazer o mesmo trabalho em menos linhas de código.
Jaskaran Singh