راه ها
Paths یک کلاس بسیار ساده با یک متد استاتیک است: get() . این فقط برای دریافت یک شی Path از رشته یا URI ایجاد شده است. کارکرد دیگری ندارد. در اینجا یک نمونه از آن در محل کار آمده است:import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
public static void main(String[] args) {
Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt");
}
}
پیچیده ترین کلاس نیست، درست است؟ :) خب، ما هم این نوع Path را داریم . بیایید بفهمیم Path چیست و چرا به آن نیاز است :)
مسیر
Path ، به طور کلی، یک آنالوگ بازطراحی شده از کلاس File است . کار با آن بسیار ساده تر از File است . ابتدا ، بسیاری از متدهای کاربردی (استاتیک) خارج شدند و به کلاس Files منتقل شدند . دوم ، نظم بر مقادیر بازگشتی متدهای واسط Path اعمال شد . در کلاس File ، متدها یک String یا یک Boolean یا یک File را برمیگردانند . فهمیدن آن آسان نبود. به عنوان مثال، یک متد getParent() وجود داشت که یک رشته نشان دهنده مسیر والد فایل فعلی را برمی گرداند. اما یک متد getParentFile() نیز وجود داشت که همان چیزی را برمی گرداند اما به شکل یک شی File ! این به وضوح زائد است. بر این اساس، در رابط Path ، متد getParent() و سایر روشها برای کار با فایلها به سادگی یک شی Path را برمیگردانند . بدون انبوهی از گزینه ها - همه چیز آسان و ساده است. برخی از روش های مفیدی که Path دارد چیست ؟ در اینجا برخی از آنها و نمونه هایی از نحوه کار آنها آورده شده است:-
getFileName() : نام فایل را از مسیر برمی گرداند.
-
getParent() : دایرکتوری "parent" مسیر فعلی را برمی گرداند (به عبارت دیگر، دایرکتوری واقع در بالای درخت دایرکتوری).
-
getRoot() : دایرکتوری "root" یعنی دایرکتوری بالای درخت دایرکتوری را برمی گرداند.
-
startsWith() , endsWith() : بررسی کنید که آیا مسیر با مسیر عبور شده شروع/پایان مییابد:
import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt"); Path fileName = testFilePath.getFileName(); System.out.println(fileName); Path parent = testFilePath.getParent(); System.out.println(parent); Path root = testFilePath.getRoot(); System.out.println(root); boolean endWithTxt = testFilePath.endsWith("Desktop\\testFile.txt"); System.out.println(endWithTxt); boolean startsWithLalala = testFilePath.startsWith("lalalala"); System.out.println(startsWithLalala); } }
خروجی کنسول:
testFile.txt C:\Users\Username\Desktop C:\ true false
به نحوه عملکرد متد endsWith() توجه کنید . بررسی می کند که آیا مسیر فعلی به مسیر عبور شده ختم می شود یا خیر . به طور خاص، چه در مسیر باشد ، نه در رشته عبور .
نتایج این دو فراخوان را مقایسه کنید:
import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt"); System.out.println(testFilePath.endsWith("estFile.txt")); System.out.println(testFilePath.endsWith("Desktop\\testFile.txt")); } }
خروجی کنسول:
false true
متد endsWith() باید از یک مسیر واقعی عبور کند، نه فقط مجموعه ای از کاراکترها: در غیر این صورت، نتیجه همیشه نادرست خواهد بود، حتی اگر مسیر فعلی واقعاً با آن دنباله از کاراکترها به پایان برسد (همانطور که در مورد "estFile.txt وجود دارد" "در مثال بالا).
علاوه بر این، Path گروهی از متدها دارد که کار با مسیرهای مطلق (کامل) و نسبی را ساده می کند .
-
اگر مسیر فعلی مطلق باشد، isAbsolute() بولی true برمی گرداند:
import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath = Paths.get("C:\\Users\\Username\\Desktop\\testFile.txt"); System.out.println(testFilePath.isAbsolute()); } }
خروجی کنسول:
true
-
Path normalize() : مسیر فعلی را "نرمال" می کند و عناصر غیر ضروری را از آن حذف می کند. ممکن است بدانید که در سیستم عامل های محبوب نمادهای "." (دایرکتوری فعلی) و ".." (دایرکتوری والد) اغلب برای تعیین مسیرها استفاده می شوند. به عنوان مثال، " ./Pictures/dog.jpg " به این معنی است که دایرکتوری فعلی دارای یک پوشه "Pictures" است که به نوبه خود حاوی یک فایل "dog.jpg" است.
اینجا را نگاه کن. اگر مسیری با استفاده از "." یا ".." در برنامه شما ظاهر می شود، متد normalize() آنها را حذف می کند و مسیری را تولید می کند که حاوی آنها نباشد:
import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path path5 = Paths.get("C:\\Users\\Java\\.\\examples"); System.out.println(path5.normalize()); Path path6 = Paths.get("C:\\Users\\Java\\..\\examples"); System.out.println(path6.normalize()); } }
خروجی کنسول:
C:\Users\Java\examples C:\Users\examples
-
Path relativize() : مسیر نسبی بین مسیر فعلی و مسیر عبوری را محاسبه می کند.
مثلا:
import java.nio.file.Path; import java.nio.file.Paths; public class Main { public static void main(String[] args) { Path testFilePath1 = Paths.get("C:\\Users\\Users\\Users\\Users"); Path testFilePath2 = Paths.get("C:\\Users\\Users\\Users\\Users\\Username\\Desktop\\testFile.txt"); System.out.println(testFilePath1.relativize(testFilePath2)); } }
خروجی کنسول:
Username\Desktop\testFile.txt
فایل ها
Files یک کلاس کاربردی است که متدهای ثابت خارج شده از کلاس File را نگهداری می کند . فایل ها با آرایه ها یا مجموعه ها قابل مقایسه هستند. تفاوت این است که با فایل ها کار می کند نه آرایه ها یا مجموعه ها :) روی مدیریت فایل ها و دایرکتوری ها تمرکز دارد. با استفاده از متدهای ثابت کلاس Files می توانیم فایل ها و دایرکتوری ها را ایجاد، حذف و انتقال دهیم. این عملیات با استفاده از متدهای createFile() (برای دایرکتوری ها، createDirectory() )، move() و delete() انجام می شود . در اینجا نحوه استفاده از آنها آمده است:import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
public class Main {
public static void main(String[] args) throws IOException {
// Create a file
Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
System.out.println("Was the file created successfully?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
// Create a directory
Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
System.out.println("Was the directory created successfully?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));
// Move the file from the desktop to the testDirectory directory. When you move a folder, you need to indicate its name in the folder!
testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);
System.out.println("Did our file remain on the desktop?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
System.out.println("Has our file been moved to testDirectory?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));
// Delete a file
Files.delete(testFile1);
System.out.println("Does the file still exist?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt")));
}
}
در اینجا ابتدا یک فایل ( روش Files.createFile() ) روی دسکتاپ ایجاد می کنیم. سپس یک پوشه در همان مکان ایجاد می کنیم ( متد Files.createDirectory ). پس از آن، فایل ( روش Files.move) را از دسکتاپ به این پوشه جدید منتقل می کنیم و در نهایت فایل ( روش Files.delete() ) را حذف می کنیم. خروجی کنسول:
Was the file created successfully?
true
Was the directory created successfully?
true
Did our file remain on the desktop?
false
Has our file been moved to testDirectory?
true
Does the file still exist?
false
توجه داشته باشید:مانند متدهای واسط Path
، بسیاری از متدهای Files
کلاس یکPath
شی را برمی گرداند. اکثر متدهای کلاس Files
نیز Path
اشیا را به عنوان ورودی می گیرند. در اینجا این Paths.get()
روش دستیار وفادار شما خواهد بود - از آن به خوبی استفاده کنید. چه چیز دیگری جالب است Files
؟ چیزی که قشر قدیمی File
واقعاً کم داشتند یک copy()
روش است! در ابتدای این درس در مورد آن صحبت کردیم. اکنون زمان ملاقات با آن است!
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
public class Main {
public static void main(String[] args) throws IOException {
// Create a file
Path testFile1 = Files.createFile(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt"));
System.out.println("Was the file created successfully?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
// Create a directory
Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
System.out.println("Was the directory created successfully?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));
// Copy the file from the desktop to the testDirectory2 directory.
testFile1 = Files.copy(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt"), REPLACE_EXISTING);
System.out.println("Did our file remain on the desktop?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
System.out.println("Was our file copied to testDirectory?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
}
}
خروجی کنسول:
Was the file created successfully?
true
Was the directory created successfully?
true
Did our file remain on the desktop?
true
Was our file copied to testDirectory?
true
اکنون می دانید که چگونه فایل ها را به صورت برنامه نویسی کپی کنید! :) البته، Files
کلاس به شما امکان می دهد نه تنها یک فایل را مدیریت کنید، بلکه با محتویات آن نیز کار کنید. این write()
روش برای نوشتن داده ها در یک فایل و هر 3 روش برای خواندن داده ها دارد: read()
, readAllBytes()
, و readAllLines()
ما در مورد آخرین مورد به تفصیل صحبت خواهیم کرد. چرا اون یکی؟ چون نوع برگشتی خیلی جالبی داره: List<String>
! یعنی لیستی از تمام خطوط فایل را به ما برمی گرداند. for
البته، این کار با محتوای فایل را بسیار راحت می کند، زیرا کل فایل، خط به خط، می تواند برای مثال با استفاده از یک حلقه معمولی روی کنسول نمایش داده شود:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import static java.nio.charset.StandardCharsets.UTF_8;
public class Main {
public static void main(String[] args) throws IOException {
List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);
for (String s: lines) {
System.out.println(s);
}
}
}
خروجی کنسول:
I still recall the wondrous moment:
When you appeared before my sight,
As though a brief and fleeting omen,
Pure phantom in enchanting light.
فوق العاده راحت! :) این توانایی در جاوا 7 ظاهر شد. Stream API در جاوا 8 ظاهر شد. برخی از عناصر برنامه نویسی کاربردی را به جاوا اضافه می کند. از جمله قابلیت های مدیریت فایل غنی تر. تصور کنید که ما وظیفه زیر را داریم: تمام خطوطی که با کلمه "As" شروع می شوند را پیدا کنید، آنها را به حروف بزرگ تبدیل کنید و روی کنسول نمایش دهید. یک راه حل با استفاده از Files
کلاس در جاوا 7 چگونه خواهد بود؟ چیزی شبیه به این:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import static java.nio.charset.StandardCharsets.UTF_8;
public class Main {
public static void main(String[] args) throws IOException {
List<String> lines = Files.readAllLines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"), UTF_8);
List<String> result = new ArrayList<>();
for (String s: lines) {
if (s.startsWith("As")) {
String upper = s.toUpperCase();
result.add(upper);
}
}
for (String s: result) {
System.out.println(s);
}
}
}
خروجی کنسول:
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
ماموریت انجام شد، اما آیا فکر نمیکنید که برای چنین کار سادهای، کد ما کمی... پرمخاطب بود؟ با استفاده از جاوا 8 استریم API، راه حل بسیار زیباتر به نظر می رسد:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) throws IOException {
Stream<String> stream = Files.lines(Paths.get("C:\\Users\\Username\\Desktop\\pushkin.txt"));
List<String> result = stream
.filter(line -> line.startsWith("As"))
.map(String::toUpperCase)
.collect(Collectors.toList());
result.forEach(System.out::println);
}
}
ما به همین نتیجه رسیدیم، اما با کد بسیار کمتر! علاوه بر این، هیچ کس نمی تواند بگوید که ما "خوانایی" را از دست داده ایم. فکر میکنم حتی بدون آشنایی با Stream API، میتوانید به راحتی درباره کاری که این کد انجام میدهد نظر دهید. به طور خلاصه، جریان مجموعه ای از عناصر است که می توانید عملیات مختلفی را روی آن انجام دهید. یک شی Stream از متد دریافت می کنیم Files.lines()
و سپس 3 تابع را به آن اعمال می کنیم:
-
ما از این
filter()
روش برای انتخاب تنها خطوطی از فایل استفاده می کنیم که با "As" شروع می شوند. -
با استفاده از روش تمام خطوط انتخاب شده را طی می کنیم
map()
و هر کدام را به حروف بزرگ تبدیل می کنیم. -
ما از
collect()
روشی برای جمع آوری تمام خطوط دریافتی در یک استفاده می کنیمList
.
AS THOUGH A BRIEF AND FLEETING OMEN,
PURE PHANTOM IN ENCHANTING LIGHT.
حالا برگردیم به نان و کره خود یعنی فایل ها :) آخرین قابلیتی که امروز در نظر می گیریم قدم زدن در درخت فایل است . در سیستم عامل های مدرن، ساختار فایل اغلب شبیه یک درخت است: دارای یک ریشه است و شاخه هایی وجود دارد که می توانند شاخه های دیگری داشته باشند و غیره. ریشه و شاخه ها دایرکتوری هستند. برای مثال، دایرکتوری " С:// " ممکن است ریشه باشد. این شامل دو شاخه است: " C://Downloads " و " C://Users ". هر یک از این شاخه ها دارای دو شاخه هستند: " C://Downloads/Pictures ", " C://Downloads/Video "، " C://Users/JohnSmith "، " C://Users/Pudge2005 ". و این شاخه ها به نوبه خود دارای شاخه های دیگری و غیره هستند و به همین دلیل است که به آن درخت می گوییم. در لینوکس، ساختار مشابه است، اما دایرکتوری /





Files.walkFileTree ()
. این چیزی است که ما باید انجام دهیم. ابتدا به یک FileVisitor
. FileVisitor
یک رابط ویژه است که در آن روش های پیمایش درخت فایل توضیح داده شده است. به ویژه، اینجاست که منطق خواندن محتویات یک فایل و بررسی اینکه آیا متن مورد نیاز ما در آن وجود دارد یا خیر را قرار می دهیم. در اینجا FileVisitor
به نظر می رسد ما چگونه است:
import java.io.IOException;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.List;
public class MyFileVisitor extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
List<String> lines = Files.readAllLines(file);
for (String s: lines) {
if (s.contains("This is the file we need")) {
System.out.println("We found a file we need!");
System.out.println(file.toAbsolutePath());
break;
}
}
return FileVisitResult.CONTINUE;
}
}
در این حالت کلاس ما ارث می برد SimpleFileVisitor
. این کلاسی است که پیادهسازی میکند FileVisitor
و در آن باید فقط یک متد را نادیده بگیریم: visitFile()
. در اینجا ما تعریف می کنیم که با هر فایل در هر دایرکتوری چه کاری باید انجام شود. اگر به منطق پیچیده تری برای پیمایش ساختار فایل نیاز دارید، باید پیاده سازی خود را بنویسید FileVisitor
. شما باید 3 متد دیگر را در آن کلاس پیاده سازی کنید:
-
preVisitDirectory()
: منطقی که باید قبل از ورود به پوشه اجرا شود. -
visitFileFailed()
: منطقی که در صورت عدم امکان بازدید از فایل (بدون دسترسی یا به دلایل دیگر) اجرا می شود. -
postVisitDirectory()
: منطقی که باید بعد از وارد کردن پوشه اجرا شود.
SimpleFileVisitor
. منطق داخل visitFile()
روش بسیار ساده است: تمام خطوط فایل را بخوانید، بررسی کنید که آیا محتوای مورد نیاز ما را شامل می شود یا خیر، و اگر چنین است، مسیر مطلق را روی کنسول چاپ کنید. تنها خطی که ممکن است برای شما مشکل ایجاد کند این است:
return FileVisitResult.CONTINUE;
در واقع، این بسیار ساده است. در اینجا ما به سادگی توضیح می دهیم که برنامه پس از بازدید از فایل و انجام کلیه عملیات لازم چه کاری باید انجام دهد. در مورد ما، ما می خواهیم به پیمایش درخت ادامه دهیم، بنابراین CONTINUE
گزینه را انتخاب می کنیم. اما، در عوض، ممکن است هدف دیگری داشته باشیم: به جای یافتن همه فایلهایی که حاوی «این فایلی است که ما نیاز داریم» را پیدا کنیم، فقط یک فایل را پیدا کنیم . پس از آن، برنامه باید خاتمه یابد. در این مورد، کد ما دقیقاً یکسان به نظر می رسد، اما به جای break وجود خواهد داشت:
return FileVisitResult.TERMINATE;
خوب، بیایید کد خود را اجرا کنیم و ببینیم که آیا کار می کند یا خیر.
import java.io.IOException;
import java.nio.file.*;
public class Main {
public static void main(String[] args) throws IOException {
Files.walkFileTree(Paths.get("C:\\Users\\Username\\Desktop\\testFolder"), new MyFileVisitor());
}
}
خروجی کنسول:
We found a file we need!
C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt
We found a file we need!
C:\Users\Username\Desktop\testFolder\level1-a\level2-a-a\FileWeNeed2.txt
We found a file we need!
C:\Users\Username\Desktop\testFolder\level1-b\level2-b-b\FileWeNeed3.txt
عالی! کار کرد! :) شما همچنین می توانید این چالش کوچک را بپذیرید: SimpleFileVisitor
با یک معمولی جایگزین کنید FileVisitor
، هر 4 روش را نادیده بگیرید و هدف خود را برای برنامه ایجاد کنید. به عنوان مثال، میتوانید برنامهای بنویسید که تمام اقدامات خود را ثبت کند: نام فایل یا پوشه را قبل یا بعد از وارد کردن آنها نمایش دهید. فعلاً همین است. به زودی میبینمت! :)
GO TO FULL VERSION