Как я могу получить размер папки или файла в Java?
источник
Как я могу получить размер папки или файла в Java?
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
. Кроме того, он не учитывает символические ссылки и, возможно, имеет другие режимы сбоя. Воспользуйтесь этим методом .
NullPointerException
если каталог одновременно изменен.
Используя 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();
}
AtomicLong
вместо просто long
?
Files
он не поддерживает его напрямую!
Вам нужно FileUtils#sizeOfDirectory(File)
от commons-io .
Обратите внимание, что вам нужно будет вручную проверить, является ли файл каталогом, поскольку метод выдает исключение, если ему передается не каталог.
ПРЕДУПРЕЖДЕНИЕ : этот метод (по состоянию на commons-io 2.4) содержит ошибку и может вызывать ошибку, IllegalArgumentException
если каталог одновременно изменяется.
checkDirectory(directory);
проверки. Просто убедитесь, что у File.listFiles
него есть дети. Ссылки : FileUtils.sizeOfDirectory () , File.listFiles ()
IllegalArgumentException
если каталог изменен во время итерации.
В Java 8:
long size = Files.walk(path).mapToLong( p -> p.toFile().length() ).sum();
Было бы лучше использовать Files::size
на этапе карты, но он выдает проверенное исключение.
ОБНОВЛЕНИЕ:
вы также должны знать, что это может вызвать исключение, если некоторые файлы / папки недоступны. См. Этот вопрос и другое решение с использованием Guava .
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;
}
size += getFolderSize(file);
Для Java 8 это один из правильных способов:
Files.walk(new File("D:/temp").toPath())
.map(f -> f.toFile())
.filter(f -> f.isFile())
.mapToLong(f -> f.length()).sum()
Важно отфильтровать все каталоги , поскольку не гарантируется, что метод length для каталогов будет равен 0.
По крайней мере, этот код предоставляет такую же информацию о размере, как и сам проводник Windows.
Вот лучший способ получить общий размер файла (работает для каталога и не каталога):
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;
}
Изменить: обратите внимание, что это, вероятно, займет много времени. Не запускайте его в потоке пользовательского интерфейса.
Кроме того, здесь (взято из https://stackoverflow.com/a/5599842/1696171 ) - хороший способ получить читаемую пользователем строку из возвращенного long:
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];
}
Если вы хотите использовать Java 8 NIO 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
объектов, поэтому он также работает для файлов.
Обратите внимание : если файл или каталог недоступны, в этом случае возвращаемый размер объекта пути будет 0
.
У File
объекта есть length
метод:
f = new File("your/file/name");
f.length();
Исходный код:
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());
}
для окон, использующих 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;
}
Это проверено и работает на моей стороне.
Я тестировал du -c <folderpath>
и работает в 2 раза быстрее, чем 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;
}
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 не может получить размер папки.Этот метод не подходит для многопоточного сценария.
Прежде всего, я хочу проверить правильность каталогов при просмотре дерева файловой системы.
private static boolean isValidDir(File dir){
if (dir != null && dir.exists() && dir.isDirectory()){
return true;
}else{
return false;
}
}
Во-вторых, я не хочу, чтобы мой рекурсивный вызов переходил в символические ссылки (softlinks) и включал размер в общую совокупность.
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 (). Согласно 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;
}
}
Немного крема на торте, API для получения размера списка файлов (могут быть все файлы и папка в корневом каталоге).
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;
}
в linux, если вы хотите отсортировать каталоги, тогда du -hs * | sort -h
Вы можете использовать, 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>
Если вы не являетесь поклонником Maven, загрузите следующую банку и добавьте ее в путь к классам.
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;
}
StatFs
. Он использует статистику файловой системы и почти в 1000 раз быстрее, чем рекурсивные методы, которые мы не могли использовать. Нашу реализацию можно найти здесь: stackoverflow.com/a/58418639/293280