Nhận kích thước của thư mục hoặc tệp


105

Làm cách nào để truy xuất kích thước của thư mục hoặc tệp trong Java?



Nếu bạn đang sử dụng Android thì hãy xem StatFs. Nó sử dụng thống kê hệ thống tệp và nhanh hơn gần 1000 lần so với các phương pháp đệ quy, không sử dụng được cho nhu cầu của chúng tôi. Thực hiện của chúng tôi có thể tìm thấy ở đây: stackoverflow.com/a/58418639/293280
Joshua Pinter

Câu trả lời:


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

Điều này trả về độ dài của tệp tính bằng byte hoặc 0nếu tệp không tồn tại. Không có cách nào tích hợp sẵn để lấy kích thước của một thư mục, bạn sẽ phải duyệt đệ quy cây thư mục (sử dụng listFiles()phương thức của một đối tượng tệp đại diện cho một thư mục) và tích lũy kích thước thư mục cho chính mình:

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

CẢNH BÁO : Phương pháp này không đủ mạnh để sử dụng trong sản xuất. directory.listFiles()có thể trở lại nullvà gây ra a NullPointerException. Ngoài ra, nó không xem xét các liên kết tượng trưng và có thể có các chế độ lỗi khác. Sử dụng phương pháp này .


11
Hãy cẩn thận nếu bạn chạy điều này trong thư mục gốc C: trên máy Windows; có một tệp hệ thống ở đó (theo java.io.File) không phải là tệp cũng như thư mục. Bạn có thể muốn thay đổi mệnh đề else để kiểm tra xem Tệp có thực sự là một thư mục hay không.
Paul Clapham

2
Thay đổi đơn giản để kiểm tra tham số để xem nếu nó không phải là một thư mục ở đầu phương thức và trả về độ dài sau đó đệ quy đơn giản hơn - chỉ cần thêm lệnh gọi đến self trong cùng một phương thức và sau đó điều này hỗ trợ việc chuyển vào tham chiếu tệp thay thế của một thư mục.
Kevin Brock

3
Nếu bạn sử dụng Java 7 trở lên, hãy sử dụng câu trả lời stackoverflow.com/a/19877372/40064, nó nhanh hơn rất nhiều.
Wim Deblauwe

1
Điều này sẽ bị nhầm lẫn bởi các liên kết tượng trưng. Ngoài ra, nó có thể ném ra NullPointerExceptionnếu thư mục được sửa đổi đồng thời.
Aleksandr Dubinsky

43

Sử dụng java-7 nio api, việc tính toán kích thước thư mục có thể được thực hiện nhanh hơn rất nhiều.

Đây là một ví dụ sẵn sàng để chạy, mạnh mẽ và sẽ không đưa ra ngoại lệ. Nó sẽ ghi lại các thư mục mà nó không thể nhập hoặc gặp sự cố khi duyệt. Các liên kết tượng trưng bị bỏ qua và việc sửa đổi đồng thời thư mục sẽ không gây ra nhiều rắc rối hơn mức cần thiết.

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

Có tương đương cho điều này trên phát triển Android không?
nhà phát triển android

Có một lý do để sử dụng AtomicLongthay vì chỉ long?
Lukas Schmelzeisen

Biến phải là biến cuối cùng khi được truy cập từ lớp ẩn danh
Aksel Willgert

1
Tôi đã thực hiện một điểm chuẩn bằng cách sử dụng JMH và phương pháp NIO api này nhanh hơn khoảng 4 đến 5 lần so với mã commons-io (được thử nghiệm trên một thư mục có nhiều thư mục con với tổng số 180229 tệp). Commons IO mất 15 giây, NIO mất 5 giây.
Wim Deblauwe

3
Cách tiếp cận này là mạnh mẽ nhất. Nó xử lý các liên kết tượng trưng, ​​sửa đổi đồng thời, các ngoại lệ bảo mật, hoạt động với cả tệp và thư mục, v.v. Nó quá tệ Fileskhi không hỗ trợ trực tiếp!
Aleksandr Dubinsky

38

Bạn cần FileUtils#sizeOfDirectory(File)từ commons-io .

Lưu ý rằng bạn sẽ cần phải kiểm tra thủ công xem tệp có phải là một thư mục hay không vì phương pháp ném một ngoại lệ nếu một thư mục không phải được chuyển đến nó.

CẢNH BÁO : Phương pháp này (kể từ commons-io 2.4) có một lỗi và có thể bị lỗi IllegalArgumentExceptionnếu thư mục được sửa đổi đồng thời.


Vì vậy, điều gì sẽ xảy ra khi tệp không phải là một thư mục? khi nó không tồn tại? vv - tài liệu kinh khủng làm sao
Mr_and_Mrs_D

@Mr_and_Mrs_D - Chỉ cần sao chép và dán các dòng sau khi checkDirectory(directory);kiểm tra. Chỉ cần đảm bảo rằng File.listFilescó trẻ em. Refs: FileUtils.sizeOfDirectory () , File.listFiles ()
Mr. Polywhirl

3
Xem lỗi IO-449 . Phương thức này sẽ ném một IllegalArgumentExceptionnếu thư mục được sửa đổi trong khi nó đang lặp lại.
Aleksandr Dubinsky

oái !!! Điều đó thật tệ ... vâng, nó liệt kê các tệp và sau đó nếu một tệp bị xóa trong khi mã đang chạy, nó sẽ ném.
Dean Hiller

19

Trong Java 8:

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

Nó sẽ đẹp hơn nếu sử dụng Files::sizetrong bước bản đồ nhưng nó ném ra một ngoại lệ đã được kiểm tra.

CẬP NHẬT:
Bạn cũng nên biết rằng điều này có thể tạo ra một ngoại lệ nếu một số tệp / thư mục không thể truy cập được. Xem câu hỏi này và một giải pháp khác bằng Guava .


1
tôi đã tìm kiếm một thứ tương tự và kết thúc với mã được đề cập: stackoverflow.com/questions/22867286/… , như bạn thấy có một khía cạnh khác của việc xử lý lỗi cũng gây ra sự cố.
Aksel Willgert

@AkselWillgert Cảm ơn, điều này thật không may và tôi đã cập nhật câu trả lời. Hiện đang chuyển sang 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 mã của bạn cần phải có một bản sửa lỗi đơn giản, trong cuộc gọi đệ quy, bạn nên thêm kích thước vào kích thước hiện có chứ không chỉ gán cho nó. size += getFolderSize(file);
Teja Kantamneni

@Teja: Cảm ơn bạn đã chỉ ra, nhưng những thay đổi cũng sẽ có trong câu lệnh if
Vishal

Đôi khi trên một thư mục đang phát triển (một chuỗi khác đang tải xuống các tệp và thư mục đồng thời tôi đang in kích thước thư mục khi đang tiến hành) nó đưa ra nullpointerexception tại dòng "for (Tệp: dir.listFiles ()) {". Một số tệp xuất hiện và biến mất nhanh chóng trên một thư mục sống. Vì vậy, tôi đã thêm một kiểm tra null cho giá trị trả về dir.listFiles () trước vòng lặp for.
csonuryilmaz

Từ File.listFiles () javadoc: "Mảng sẽ trống nếu thư mục trống. Trả về giá trị rỗng nếu tên đường dẫn trừu tượng này không biểu thị một thư mục hoặc nếu xảy ra lỗi I / O." Vì vậy, nhận xét trên rất hữu ích khi nhận được kích thước thư mục trên các thư mục thay đổi động.
csonuryilmaz

7

Đối với Java 8, đây là một cách đúng đắn để làm điều đó:

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

Điều quan trọng là phải lọc ra tất cả các thư mục , vì phương thức length không được đảm bảo là 0 cho các thư mục.

Ít nhất thì mã này cung cấp thông tin về kích thước giống như chính Windows Explorer.


4

Đây là cách tốt nhất để có được kích thước chung của Tệp (hoạt động cho thư mục và không phải thư mục):

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

Chỉnh sửa: Lưu ý rằng đây có thể sẽ là một hoạt động tốn thời gian. Đừng chạy nó trên chuỗi giao diện người dùng.

Ngoài ra, đây (được lấy từ https://stackoverflow.com/a/5599842/1696171 ) là một cách hay để có được Chuỗi người dùng có thể đọc được từ lâu được trả về:

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

Nếu bạn muốn sử dụng Java 8 NIO API, chương trình sau sẽ in ra kích thước, tính bằng byte, của thư mục mà nó nằm trong đó.

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

}

Các calculateSizephương pháp mang tính phổ quát cho Pathđối tượng, vì vậy nó cũng làm việc cho các tập tin. Lưu ý rằng nếu một tệp hoặc thư mục không thể truy cập được, trong trường hợp này, kích thước trả về của đối tượng đường dẫn sẽ là 0.


3

File.length()( Javadoc ).

Lưu ý rằng điều này không hoạt động cho các thư mục hoặc không được đảm bảo hoạt động.

Đối với một thư mục, bạn muốn gì? Nếu đó là tổng kích thước của tất cả các file bên dưới nó, bạn có thể đi bộ một cách đệ quy trẻ em sử dụng File.list()File.isDirectory()và tổng kích thước của chúng.


3

Đối Filetượng có một lengthphương thức:

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

3
  • Hoạt động cho AndroidJava
  • Hoạt động cho cả thư mục và tệp
  • Kiểm tra con trỏ rỗng ở mọi nơi nếu cần
  • Bỏ qua liên kết tượng trưng hay còn gọi là phím tắt
  • Sản xuất đã sẵn sàng!

Mã nguồn:

   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

đối với windows, sử dụng java.io, hàm reccursive này rất hữu ích.

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

Điều này đã được kiểm tra và hoạt động tốt trên đầu của tôi.


1

Tôi đã thử nghiệm du -c <folderpath>và nhanh hơn gấp 2 lần so với nio.

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

Sau rất nhiều nghiên cứu và xem xét các giải pháp khác nhau được đề xuất ở đây tại StackOverflow. Cuối cùng tôi quyết định viết giải pháp của riêng mình. Mục đích của tôi là có cơ chế no-throw vì tôi không muốn gặp sự cố nếu API không thể tìm nạp kích thước thư mục. Phương pháp này không phù hợp với kịch bản mult-threaded.

Trước hết, tôi muốn kiểm tra các thư mục hợp lệ trong khi duyệt xuống cây hệ thống tệp.

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

Thứ hai, tôi không muốn lời gọi đệ quy của mình đi vào các liên kết tượng trưng (liên kết mềm) và bao gồm tổng kích thước trong tổng số.

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

Cuối cùng, triển khai dựa trên đệ quy của tôi để tìm nạp kích thước của thư mục được chỉ định. Lưu ý kiểm tra null cho dir.listFiles (). Theo javadoc, phương thức này có thể trả về 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;
    }
}

Một ít kem trên bánh, API để lấy kích thước của danh sách Tệp (có thể là tất cả các tệp và thư mục dưới gốc).

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

trong linux nếu bạn muốn sắp xếp thư mục thì du -hs * | sắp xếp -h


0

Bạn có thể sử dụng Apache Commons IOđể tìm kích thước thư mục một cách dễ dàng.

Nếu bạn đang sử dụng maven, vui lòng thêm phần phụ thuộc sau vào pom.xmltệp của bạn .

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

Nếu không phải là fan của Maven, hãy tải xuống jar sau và thêm nó vào đường dẫn lớp.

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
}

Để nhận kích thước tệp qua Commons IO,

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

long fileSize = FileUtils.sizeOf(file);

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

Nó cũng có thể đạt được thông qua Google Guava

Đối với Maven, hãy thêm những thứ sau:

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

Nếu không sử dụng Maven, hãy thêm phần sau vào đường dẫn lớp

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

Để có kích thước tệp,

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

Mặc dù mã của bạn có vẻ tốt, nhưng tôi không chắc nó bổ sung bất cứ điều gì cho các câu trả lời khác. Nếu đúng, vui lòng chỉnh sửa câu trả lời của bạn để giải thích.
Dragonthoughts

Nó chỉ là một phiên bản cập nhật của việc thực hiện cùng một công việc với ít dòng mã hơn.
Jaskaran Singh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.