Java에서 폴더 또는 파일의 크기를 검색하려면 어떻게해야합니까?
StatFs
. 파일 시스템 통계를 사용하며 우리의 필요에 따라 사용할 수 없었던 재귀 적 방법보다 거의 1000 배 더 빠릅니다. 우리의 구현은 다음에서 찾을 수 있습니다 : stackoverflow.com/a/58418639/293280
Java에서 폴더 또는 파일의 크기를 검색하려면 어떻게해야합니까?
StatFs
. 파일 시스템 통계를 사용하며 우리의 필요에 따라 사용할 수 없었던 재귀 적 방법보다 거의 1000 배 더 빠릅니다. 우리의 구현은 다음에서 찾을 수 있습니다 : stackoverflow.com/a/58418639/293280
답변:
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를 사용하면 폴더 크기를 훨씬 빠르게 계산할 수 있습니다.
다음은 강력하고 예외를 발생시키지 않는 실행할 준비가 된 예제입니다. 입력 할 수 없거나 통과하는 데 문제가있는 디렉터리를 기록합니다. Symlink는 무시되며 디렉토리를 동시에 수정해도 필요 이상으로 문제가 발생하지 않습니다.
/**
* 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
직접 지원하지 않습니다!
commons-ioFileUtils#sizeOfDirectory(File)
에서 필요합니다 .
비 디렉토리가 전달되면 메소드에서 예외가 발생하므로 파일이 디렉토리인지 수동으로 확인해야합니다.
경고 :이 메소드 (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);
일반적인 파일의 크기를 얻는 가장 좋은 방법은 다음과 같습니다 (디렉토리 및 비 디렉토리에서 작동).
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 에서 가져옴 )는 반환 된 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
.
소스 코드:
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;
}
이것은 테스트를 거쳐 제대로 작동합니다.
테스트를 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;
}
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;
}
}
둘째, 재귀 호출이 심볼릭 링크 (소프트 링크)로 이동하고 전체 집계에 크기를 포함하는 것을 원하지 않습니다.
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;
}
}
케이크에 약간의 크림, 목록 파일의 크기를 가져 오는 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;
}
당신은 사용할 수 있습니다 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의 팬이 아니라면 다음 jar를 다운로드하여 클래스 경로에 추가하십시오.
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;
}