ฉันจะดึงขนาดของโฟลเดอร์หรือไฟล์ใน Java ได้อย่างไร?
StatFs
นั้นจะดูที่ ใช้สถิติระบบไฟล์และเร็วกว่าวิธีการเรียกซ้ำเกือบ 1,000 เท่าซึ่งใช้ไม่ได้กับความต้องการของเรา การใช้งานของเราสามารถพบได้ที่นี่: stackoverflow.com/a/58418639/293280
ฉันจะดึงขนาดของโฟลเดอร์หรือไฟล์ใน Java ได้อย่างไร?
StatFs
นั้นจะดูที่ ใช้สถิติระบบไฟล์และเร็วกว่าวิธีการเรียกซ้ำเกือบ 1,000 เท่าซึ่งใช้ไม่ได้กับความต้องการของเรา การใช้งานของเราสามารถพบได้ที่นี่: 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
นอกจากนี้ยังไม่พิจารณา symlink และอาจมีโหมดความล้มเหลวอื่น ๆ ใช้วิธีนี้ .
NullPointerException
กรณีที่มีการแก้ไขไดเร็กทอรีพร้อมกัน
การใช้ java-7 nio api การคำนวณขนาดโฟลเดอร์สามารถทำได้เร็วกว่ามาก
นี่คือตัวอย่างพร้อมใช้งานที่มีประสิทธิภาพและจะไม่เกิดข้อยกเว้น จะบันทึกไดเรกทอรีที่ไม่สามารถเข้าหรือมีปัญหาในการข้ามผ่าน Symlinks จะถูกละเว้นและการแก้ไขไดเร็กทอรีพร้อมกันจะไม่ทำให้เกิดปัญหามากเกินความจำเป็น
/**
* 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
แทน just long
หรือไม่?
Files
ไม่รองรับโดยตรง!
คุณต้องFileUtils#sizeOfDirectory(File)
จากคอมมอน-io
โปรดทราบว่าคุณจะต้องตรวจสอบด้วยตนเองว่าไฟล์นั้นเป็นไดเร็กทอรีหรือไม่เนื่องจากเมธอดจะแสดงข้อยกเว้นหากมีการส่งผ่านที่ไม่ใช่ไดเร็กทอรีไป
คำเตือน : วิธีนี้ (ณ commons-io 2.4) มีข้อผิดพลาดและอาจเกิดข้อผิดพลาดIllegalArgumentException
หากมีการแก้ไขไดเร็กทอรีพร้อมกัน
checkDirectory(directory);
เครื่องหมายถูก ตรวจสอบให้แน่ใจว่าFile.listFiles
มีบุตร Refs: FileUtils.sizeOfDirectory () , File.listFiles ()
ใน Java 8:
long size = Files.walk(path).mapToLong( p -> p.toFile().length() ).sum();
มันจะดีกว่าที่จะใช้Files::size
ในขั้นตอนแผนที่ แต่มันมีข้อยกเว้นที่ตรวจสอบแล้ว
อัปเดต:
คุณควรทราบด้วยว่าสิ่งนี้สามารถทำให้เกิดข้อยกเว้นได้หากไม่สามารถเข้าถึงไฟล์ / โฟลเดอร์บางส่วนได้ เห็นนี้คำถามและแก้ปัญหาอื่นโดยใช้ฝรั่ง
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()
การกรองไดเรกทอรีทั้งหมดเป็นสิ่งสำคัญเนื่องจากวิธีการความยาวไม่รับประกันว่าจะเป็น 0 สำหรับไดเรกทอรี
อย่างน้อยรหัสนี้ก็ให้ข้อมูลขนาดเดียวกันกับที่ Windows Explorer ทำ
นี่คือวิธีที่ดีที่สุดในการรับขนาดไฟล์ทั่วไป (ใช้ได้กับไดเร็กทอรีและไม่ใช่ไดเร็กทอรี):
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 ) เป็นวิธีที่ดีในการรับสตริงที่ผู้ใช้อ่านได้จากการส่งคืนแบบยาว:
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()
( Javadoc ).
โปรดทราบว่าสิ่งนี้ใช้ไม่ได้กับไดเรกทอรีหรือไม่รับประกันว่าจะใช้งานได้
สำหรับไดเร็กทอรีคุณต้องการอะไร หากเป็นขนาดรวมของไฟล์ทั้งหมดที่อยู่ข้างใต้คุณสามารถเดินวนซ้ำ ๆ โดยใช้File.list()
และรวมขนาดของไฟล์เหล่านั้นFile.isDirectory()
ได้
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());
}
สำหรับ 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;
}
}
ประการที่สองฉันไม่ต้องการให้การเรียกซ้ำของฉันไปที่ symlinks (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 มีความเป็นไปได้ที่วิธีนี้สามารถคืนค่าว่างได้
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 * | เรียงลำดับ -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 ให้ดาวน์โหลด 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;
}