获取文件夹或文件的大小

如何在 Java 中检索文件夹或文件的大小?

133309 次浏览

File.length()(贾瓦多克).

注意,这对目录不起作用,或者不能保证起作用。

对于一个目录,您需要什么?如果是它下面所有文件的总大小,您可以使用 File.list()File.isDirectory()递归地遍历子文件并对它们的大小进行求和。

File对象有一个 length方法:

f = new File("your/file/name");
f.length();
java.io.File file = new java.io.File("myfile.txt");
file.length();

如果文件不存在,则返回以字节为单位的文件长度或 0。没有获得文件夹大小的内置方法,你必须递归地遍历目录树(使用代表一个目录的文件对象的 listFiles()方法)并为自己积累目录大小:

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

警告 : 此方法对于生产使用来说不够健壮。directory.listFiles()可能返回 null并导致 NullPointerException。此外,它不考虑符号链接,可能还有其他失败模式。使用 这种方法

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

你需要 FileUtils#sizeOfDirectory(File)(法语)

请注意,您需要手动检查该文件是否为目录,因为如果传递给该方法的是非目录,则该方法将引发异常。

警告 : 这个方法(就 commons-io 2.4而言)有一个 bug,如果目录被并发修改,可能会抛出 IllegalArgumentException

使用 java-7 nio api,可以更快地计算文件夹大小。

下面是一个即将运行的示例,它是健壮的,不会抛出异常。它将记录无法进入或无法遍历的目录。符号链接被忽略,并且目录的并发修改不会造成不必要的麻烦。

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

在 Java 8中:

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

在 map 步骤中使用 Files::size会更好,但它会抛出一个检查过的异常。

更新:
您还应该注意,如果某些文件/文件夹无法访问,这可能会引发异常。请参阅此 有个问题和使用 番石榴的另一种解决方案。

下面是获得常规文件大小的最佳方法(适用于目录和非目录) :

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

编辑: 请注意,这可能是一个耗时的操作。不要在 UI 线程上运行它。

此外,这里(取自 https://stackoverflow.com/a/5599842/1696171)是从长返回的字符串中获得用户可读的 String 的一种好方法:

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

经过对 StackOverflow 提出的不同解决方案的大量研究和探索。我终于决定写我自己的解决方案。我的目的是采用无抛出机制,因为如果 API 无法获取文件夹大小,我不希望崩溃。此方法不适用于多线程场景。

First of all I want to check for valid directories while traversing down the file system tree.

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

Second I do not want my recursive call to go into symlinks (softlinks) and include the size in total aggregate.

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

最后,使用基于递归的实现来获取指定目录的大小。注意 dir.listFiles ()的 null 检查。根据 javadoc,这个方法有可能返回 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;
}
}

Some cream on the cake, the API to get the size of the list Files (might be all of files and folder under root).

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

对于 爪哇8来说,这是一种正确的做法:

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

过滤掉所有的目录 非常重要,因为 length 方法不能保证目录为0。

At least this code delivers the same size information like Windows Explorer itself does.

如果要使用 Java8NIO API,下面的程序将打印它所在的目录的大小(以字节为单位)。

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


}

calculateSize方法对于 Path对象是通用的,因此它也适用于文件。 注意 ,如果文件或目录不可访问,在这种情况下,path 对象返回的 尺寸将是 0

在 linux 中,如果你想对目录进行排序,那么 du-hs * | sort-h

  • 仿生人爪哇咖啡工作
  • 适用于文件夹和文件
  • 在任何需要的地方检查空指针
  • 忽略 符号链接即快捷方式
  • 拍摄准备就绪!

源代码:

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

对于 windows,使用 java.io 这个递归函数很有用。

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

这是测试和工作正常,在我的一端。

您可以使用 Apache Commons IO轻松地查找文件夹大小。

如果您使用的是 maven,请在 pom.xml文件中添加以下依赖项。

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

If not a fan of Maven, download the following jar and add it to the class path.

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
}

要通过 Commons IO 获取文件大小,

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


long fileSize = FileUtils.sizeOf(file);


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

它也可以通过 Google Guava实现

对于 Maven,添加以下内容:

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

如果不使用 Maven,请将以下内容添加到类路径

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

要获取文件大小,

 File file = new File("PATH TO YOUR FILE");
long s  = file.length();
System.out.println(s);
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;
}

我测试过 du -c <folderpath>,它比 nio 快2倍

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;
}
fun getSize(context: Context, uri: Uri?): Float? {
var fileSize: String? = null
val cursor: Cursor? = context.contentResolver
.query(uri!!, null, null, null, null, null)
try {
if (cursor != null && cursor.moveToFirst()) {


// get file size
val sizeIndex: Int = cursor.getColumnIndex(OpenableColumns.SIZE)
if (!cursor.isNull(sizeIndex)) {
fileSize = cursor.getString(sizeIndex)
}
}
} finally {
cursor?.close()
}
return fileSize!!.toFloat() / (1024 * 1024)
}