File
. می توانید در مورد کارهای او اینجا بخوانید . اما در جاوا 7، سازندگان این زبان تصمیم گرفتند نحوه کار با فایل ها و دایرکتوری ها را تغییر دهند. این به دلیل این واقعیت بود که کلاس File
دارای یک سری معایب بود. copy()
به عنوان مثال، روشی که به شما امکان می دهد یک فایل را از یک مکان به مکان دیگر کپی کنید (یک ویژگی ظاهراً به وضوح مورد نیاز) نداشت . علاوه بر این، کلاس File
متدهای بسیار زیادی داشت که boolean
مقادیر - را برمیگرداند. اگر خطایی رخ دهد، چنین روشی به جای ایجاد استثنا، false را برمیگرداند، که تشخیص خطاها و تعیین علل آنها را بسیار دشوار میکند. به جای یک کلاس، File
به اندازه 3 کلاس ظاهر شد Paths
: Path
و Files
. خوب، به طور دقیق، Path
این یک رابط است، نه یک کلاس. بیایید بفهمیم که چگونه آنها با یکدیگر متفاوت هستند و چرا هر یک از آنها مورد نیاز است. بیایید با ساده ترین چیز شروع کنیم - Paths
.
راه ها
Paths
یک کلاس بسیار ساده با یک روش استاتیک واحد است get()
. این فقط برای به دست آوردن یک شی از نوع از رشته یا URI ایجاد شده است Path
. هیچ کارکرد دیگری ندارد. در اینجا نمونه ای از کارهای او آورده شده است:
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()
- دایرکتوری "والد" را در رابطه با مسیر فعلی (یعنی دایرکتوری که در درخت دایرکتوری بالاتر است) برمی گرداند. -
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")); } }
خروجی کنسول:
غلط
درستشما باید مسیر کامل را به متد منتقل کنید
endsWith()
، و نه فقط مجموعه ای از کاراکترها: در غیر این صورت، نتیجه همیشه نادرست خواهد بود ، حتی اگر مسیر فعلی واقعاً با چنین دنباله ای از کاراکترها پایان یابد (مانند مورد "estFile.txt" ” در مثال بالا).علاوه بر این، گروهی از روش ها وجود دارد که کار با مسیرهای مطلق (کامل) و نسبی را ساده می کند
Path
.
-
boolean 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()); } }
خروجی کنسول:
درست است، واقعی
-
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)); } }
خروجی کنسول:
نام کاربری\Desktop\testFile.txt
Path
بسیار بزرگ است. می توانید همه آنها را در اسناد Oracle بیابید . ما به بررسی خواهیم پرداخت Files
.
فایل ها
Files
- این یک کلاس کاربردی است که در آن متدهای استاتیک از کلاس منتقل شده اند File
. Files
- این تقریباً مشابه Arrays
یا است Collections
، فقط با فایل ها کار می کند، نه با آرایه ها و مجموعه ها :) روی مدیریت فایل ها و دایرکتوری ها متمرکز است. با استفاده از روش های استاتیک 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 {
//file creation
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 directory
Path testDirectory = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory"));
System.out.println("Was the directory successfully created?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory")));
//move file from desktop to testDirectory. You need to move with the name of the file in the folder!
testFile1 = Files.move(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory\\testFile111.txt"), REPLACE_EXISTING);
System.out.println("Is our file left 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")));
//remove 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()
). پس از آن، فایل (method Files.move()
) را از دسکتاپ به این پوشه جدید منتقل می کنیم و در پایان فایل (method Files.delete()
) را حذف می کنیم. خروجی کنسول: آیا فایل با موفقیت ایجاد شد؟ درست است آیا دایرکتوری با موفقیت ایجاد شد؟ true آیا فایل ما هنوز روی دسکتاپ است؟ false آیا فایل ما به testDirectory منتقل شده است؟ true آیا فایل هنوز وجود دارد؟ نادرست توجه کنید:درست مانند متدهای واسط 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 {
//file creation
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 directory
Path testDirectory2 = Files.createDirectory(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2"));
System.out.println("Was the directory successfully created?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2")));
//copy the file from the desktop to the directory testDirectory2.
testFile1 = Files.copy(testFile1, Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt"), REPLACE_EXISTING);
System.out.println("Is our file left on the desktop?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testFile111.txt")));
System.out.println("Has our file been copied to testDirectory?");
System.out.println(Files.exists(Paths.get("C:\\Users\\Username\\Desktop\\testDirectory2\\testFile111.txt")));
}
}
خروجی کنسول: آیا فایل با موفقیت ایجاد شد؟ درست است آیا دایرکتوری با موفقیت ایجاد شد؟ true آیا فایل ما هنوز روی دسکتاپ است؟ true آیا فایل ما در 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);
}
}
}
خروجی کنسول: من یک لحظه شگفت انگیز را به یاد می آورم: تو در برابر من ظاهر شدی، مانند دیدی زودگذر، مانند نابغه ای از زیبایی ناب. خیلی راحت! :) این ویژگی در جاوا 7 ظاهر شد. در جاوا 8، Stream API ظاهر شد که برخی از عناصر برنامه نویسی کاربردی را به جاوا اضافه کرد. از جمله قابلیت های غنی تر برای کار با فایل ها. تصور کنید که ما یک وظیفه داریم: تمام خطوط یک فایل که با کلمه "How" شروع می شود را پیدا کنید، آنها را به UPPER CASE تبدیل کنید و آنها را به کنسول خروجی دهید. راه حل با استفاده از کلاس 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("How")) {
String upper = s.toUpperCase();
result.add(upper);
}
}
for (String s: result) {
System.out.println(s);
}
}
}
خروجی کنسول: مانند یک چشم انداز روزه، مانند یک نابغه از زیبایی خالص. به نظر می رسد ما این کار را انجام داده ایم، اما آیا فکر نمی کنید که برای چنین کار ساده ای کد ما کمی ... پرمخاطب بود؟ با استفاده از Java 8 Stream 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("How"))
.map(String::toUpperCase)
.collect(Collectors.toList());
result.forEach(System.out::println);
}
}
ما به همین نتیجه رسیدیم، اما با کد بسیار کمتر! علاوه بر این، نمی توان گفت که ما در «خوانایی» گم شده ایم. فکر میکنم حتی اگر با Stream API آشنا نباشید، میتوانید به راحتی درباره کاری که این کد انجام میدهد، نظر دهید. اما به طور خلاصه، استریم مجموعه ای از عناصر است که می توانید عملکردهای مختلفی را بر روی آن انجام دهید. شی Stream را از متد دریافت می کنیم Files.lines()
و 3 تابع را به آن اعمال می کنیم:
-
با استفاده از روش،
filter()
فقط خطوطی را از فایل انتخاب می کنیم که با "How" شروع می شوند. -
تمام خطوط انتخاب شده را با استفاده از روش مرور می کنیم
map()
و هر کدام را به UPPER CASE می آوریم. -
تمام خطوط به دست آمده را با هم ترکیب می کنیم تا
List
ازcollect()
.
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("Required file found!");
System.out.println(file.toAbsolutePath());
break;
}
}
return FileVisitResult.CONTINUE;
}
}
در این حالت کلاس ما از SimpleFileVisitor
. این کلاسی است که پیاده سازی می کند FileVisitor
، که در آن شما باید تنها یک متد را لغو کنید: visitFile()
. در اینجا ما توضیح می دهیم که با هر فایل در هر دایرکتوری چه کاری باید انجام شود. اگر به منطق پیمایش پیچیده تری نیاز دارید، باید پیاده سازی خود را بنویسید FileVisitor
. در آنجا باید 3 روش دیگر را پیاده سازی کنید:
-
preVisitDirectory()
- منطقی که باید قبل از ورود به پوشه اجرا شود. -
visitFileFailed()
- اگر ورود به فایل غیرممکن است (عدم دسترسی یا دلایل دیگر) چه باید کرد. -
postVisitDirectory()
- منطقی که پس از ورود به پوشه باید اجرا شود.
SimpleFileVisitor
. منطق داخل روش visitFile()
بسیار ساده است: تمام خطوط فایل را بخوانید، بررسی کنید که آیا محتوای مورد نیاز ما را شامل می شود یا خیر، و اگر چنین است، مسیر مطلق را به کنسول چاپ کنید. تنها خطی که ممکن است برای شما دردسر ایجاد کند این است:
return FileVisitResult.CONTINUE;
در واقع همه چیز ساده است. در اینجا به سادگی توضیح می دهیم که برنامه پس از وارد شدن فایل و انجام تمام عملیات های لازم چه کاری باید انجام دهد. در مورد ما، ما باید به پیمایش درخت ادامه دهیم، بنابراین گزینه را انتخاب می کنیم CONTINUE
. اما ما، برای مثال، میتوانیم کار دیگری داشته باشیم: یافتن همه فایلهایی که حاوی «این فایلی است که ما نیاز داریم» را پیدا نکنیم، بلکه فقط یک فایل را پیدا کنیم . پس از این، برنامه باید خاتمه یابد. در این مورد، کد ما دقیقاً یکسان به نظر می رسد، اما به جای شکستن. خواهد کرد:
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());
}
}
خروجی کنسول: فایل مورد نیاز پیدا شد! C:\Users\Username\Desktop\testFolder\FileWeNeed1.txt فایل مورد نیاز پیدا شد! C:\Users\Username\Desktop\testFolder\level1-a\level2-aa\FileWeNeed2.txt فایل مورد نیاز پیدا شد! C:\Users\Username\Desktop\testFolder\level1-b\level2-bb\FileWeNeed3.txt عالی، ما این کار را کردیم! :) اگر می خواهید بیشتر بدانید ، این مقاله راwalkFileTree()
به شما توصیه می کنم . شما همچنین می توانید یک کار کوچک را تکمیل کنید - آن را با یک کار معمولی جایگزین کنید ، هر 4 روش را اجرا کنید و هدفی را برای این برنامه در نظر بگیرید. برای مثال، میتوانید برنامهای بنویسید که تمام اقدامات شما را ثبت کند: نام یک فایل یا پوشه را قبل/بعد از وارد کردن آنها در کنسول نمایش دهید. همین - بعداً می بینمت! :) SimpleFileVisitor
FileVisitor
GO TO FULL VERSION