ממשק ה- API של Java NIO2 Path

1. סקירה כללית

במאמר זה נלמד כיצד להשתמש ב- I / O החדש (NIO2) נָתִיב API ב- Java.

ה נָתִיב ממשקי API ב- NIO2 מהווים אחד האזורים הפונקציונליים החדשים העיקריים שנשלחו עם Java 7 ובאופן ספציפי תת קבוצה של ממשק ה- API של מערכת הקבצים החדשה לצד ממשקי API של קבצים.

2. התקנה

התמיכה ב- NIO2 כלולה ב- java.nio.file חֲבִילָה. אז הגדרת הפרויקט שלך לשימוש ב- נָתִיב ממשקי API זה רק עניין של ייבוא ​​כל החבילה הזו:

ייבא java.nio.file. *;

מכיוון שדוגמאות הקוד במאמר זה יפעלו ככל הנראה בסביבות שונות, בואו נתייחס לספריית הבית של המשתמש:

מחרוזת סטטית פרטית HOME = System.getProperty ("user.home");

משתנה זה יצביע על מיקום חוקי בכל סביבה.

ה שבילים class הוא נקודת הכניסה הראשית לכל הפעולות הכרוכות בנתיבי מערכת הקבצים. זה מאפשר לנו ליצור ולתפעל נתיבים לקבצים ולספריות.

ראוי לציין כי פעולות הנתיבים הן בעיקרן תחביריות באופיין; אין להם שום השפעה על מערכת הקבצים הבסיסית וגם למערכת הקבצים אין כל השפעה אם הם מצליחים או נכשלים. פירוש הדבר שלמעבר נתיב לא קיים כפרמטר של פעולת נתיב אין כל השפעה אם הוא מצליח או נכשל.

3. פעולות נתיב

בחלק זה נציג את התחביר הראשי המשמש בפעולות נתיב. כשמו כן הוא, נָתִיב class הוא ייצוג פרוגרמטי של נתיב במערכת הקבצים.

א נָתִיב האובייקט מכיל את שם הקובץ ואת רשימת הספריות המשמשים לבניית הנתיב ומשמש לבדיקה, איתור ושינוי קבצים.

מעמד העוזר, java.nio.file. שבילים (בצורת רבים) היא הדרך היצירתית הרשמית נָתִיב חפצים. יש לו שתי שיטות סטטיות ליצירת a נָתִיב ממחרוזת נתיב:

נתיב נתיב = Paths.get ("מחרוזת נתיב");

בין אם אנו משתמשים בקדימה או בקו נטוי בנתיב חוּט, לא משנה, ה- API פותר פרמטר זה בהתאם לדרישות מערכת הקבצים הבסיסיות.

ומ- א java.net.URI לְהִתְנַגֵד:

נתיב נתיב = Paths.get (אובייקט URI);

כעת נוכל להמשיך ולראות את אלה בפעולה.

4. יצירת נתיב

ל ליצור נָתִיב אובייקט ממחרוזת נתיב:

@Test ציבורי בטל givenPathString_whenCreatesPathObject_thenCorrect () {Path p = Paths.get ("/ articles / baeldung"); assertEquals ("\ מאמרים \ baeldung", p.toString ()); }

ה לקבל API יכול לקחת פרמטר של ארגומנטים משתנים של חלקי מחרוזת נתיב (במקרה זה, מאמרים ו ביילדונג) בנוסף לחלק הראשון (במקרה זה, מאמרים).

אם אנו מספקים חלקים אלה במקום מחרוזת נתיב שלמה, הם ישמשו לבניית אובייקט הנתיב, איננו צריכים לכלול את מפרידי השמות (קו נטוי) בחלק הארגומנטים המשתנים:

@ מבחן חלל ציבורי givenPathParts_whenCreatesPathObject_thenCorrect () {Path p = Paths.get ("/ articles", "baeldung"); assertEquals ("\ מאמרים \ baeldung", p.toString ()); }

5. אחזור מידע על נתיב

אתה יכול לחשוב על אובייקט הנתיב כאלמנטים של שם כרצף. דרך חוּט כמו E: \ baeldung \ articles \ java מורכב משלושה מרכיבי שם כלומר ביילדונג, מאמרים, ו ג'אווה. האלמנט הגבוה ביותר במבנה הספרייה יהיה ממוקם באינדקס 0, במקרה זה ביילדונג.

האלמנט הנמוך ביותר במבנה הספריה ממוקם באינדקס [n-1], איפה נ הוא מספר רכיבי השם בנתיב. האלמנט הנמוך ביותר הזה נקרא שם קובץ לא משנה אם מדובר בקובץ בפועל או לא:

@Test ציבורי בטל givenPath_whenRetrievesFileName_thenCorrect () {Path p = Paths.get ("/ articles / baeldung / logs"); נתיב fileName = p.getFileName (); assertEquals ("logs", fileName.toString ()); }

קיימות שיטות לאחזור אלמנטים בודדים לפי אינדקס:

@Test ציבורי בטל givenPath_whenRetrievesNameByIndex_thenCorrect () {Path p = Paths.get ("/ articles / baeldung / logs"); שם נתיב 0 = getName (0); נתיב שם 1 = getName (1); נתיב name2 = getName (2); assertEquals ("מאמרים", name0.toString ()); assertEquals ("baeldung", name1.toString ()); assertEquals ("יומנים", name2.toString ()); }

או תת רצף של הנתיב המשתמש בטווחי אינדקס אלה:

@Test public void givenPath_whenCanRetrieveSubsequenceByIndex_thenCorrect () {Path p = Paths.get ("/ articles / baeldung / logs"); נתיב subPath1 = p.subpath (0,1); נתיב subPath2 = p.subpath (0,2); assertEquals ("מאמרים", subPath1.toString ()); assertEquals ("מאמרים \ baeldung", subPath2.toString ()); assertEquals ("מאמרים \ baeldung \ יומני", עמ 'subpath (0, 3) .toString ()); assertEquals ("baeldung", p.subpath (1, 2) .toString ()); assertEquals ("baeldung \ logs", p.subpath (1, 3) .toString ()); assertEquals ("logs", p.subpath (2, 3) .toString ()); }

כל נתיב משויך לנתיב הורה או ריק אם לדרך אין הורה. האב של אובייקט נתיב מורכב ממרכיב השורש של הנתיב, אם קיים, ומכל אלמנט בנתיב למעט שם הקובץ. כדוגמה, דרך ההורים של /א ב ג הוא / a / b וזה של הוא אפס:

@ מבחן חלל ציבורי givenPath_whenRetrievesParent_thenCorrect () {Path p1 = Paths.get ("/ articles / baeldung / logs"); נתיב p2 = Paths.get ("/ מאמרים / באלדונג"); נתיב p3 = Paths.get ("/ מאמרים"); נתיב p4 = Paths.get ("/"); נתיב הורה 1 = p1.getParent (); נתיב parent2 = p2.getParent (); נתיב parent3 = p3.getParent (); נתיב parent4 = p4.getParenth (); assertEquals ("\ מאמרים \ baeldung", parent1.toString ()); assertEquals ("\ מאמרים", parent2.toString ()); assertEquals ("\", parent3.toString ()); assertEquals (null, parent4); }

אנו יכולים גם להשיג את יסוד השורש של נתיב:

@Test ציבורי בטל givenPath_whenRetrievesRoot_thenCorrect () {Path p1 = Paths.get ("/ articles / baeldung / logs"); נתיב p2 = Paths.get ("c: / articles / baeldung / logs"); נתיב root1 = p1.getRoot (); נתיב root2 = p2.getRoot (); assertEquals ("\", root1.toString ()); assertEquals ("c: \", root2.toString ()); }

6. מנרמל נתיב

מערכות קבצים רבות משתמשות “.” סימון לציון הספריה הנוכחית ו- “..” לציון ספריית האב. יתכן ויהיה לך מצב שבו נתיב מכיל מידע מיותר בספריה.

לדוגמה, שקול את מחרוזות הנתיב הבאות:

/baeldung/./articles /baeldung/authors/../articles / baeldung / מאמרים

כולם פותרים לאותו מיקום / baeldung / מאמרים. לשני הראשונים יש יתירות ואילו האחרון לא.

מנרמל מסלול כרוך בהסרת יתירות בו. ה Path.normalize () פעולה ניתנת למטרה זו.

דוגמה זו אמורה להסביר את עצמה כעת:

@ מבחן חלל ציבורי givenPath_whenRemovesRedundancies_thenCorrect1 () {Path p = Paths.get ("/ home /./ baeldung / articles"); נתיב cleanPath = p.normalize (); assertEquals ("\ home \ baeldung \ articles", cleanPath.toString ()); }

גם הוא:

@ מבחן חלל ציבורי givenPath_whenRemovesRedundancies_thenCorrect2 () {Path p = Paths.get ("/ home / baeldung /../ articles"); נתיב cleanPath = p.normalize (); assertEquals ("\ מאמרים ביתיים \", cleanPath.toString ()); }

7. המרת נתיב

ישנן פעולות להמרת נתיב לפורמט מצגת שנבחר. כדי להמיר נתיב כלשהו למחרוזת שניתן לפתוח מהדפדפן, אנו משתמשים ב- toUri שיטה:

@ מבחן חלל ציבורי givenPath_whenConvertsToBrowseablePath_thenCorrect () {Path p = Paths.get ("/ home / baeldung / articles.html"); URI uri = p.toUri (); assertEquals ("file: /// E: /home/baeldung/articles.html", uri.toString ()); }

אנו יכולים גם להמיר נתיב לייצוג המוחלט שלה. ה toAbsolutePath השיטה פותרת נתיב כנגד ספריית ברירת המחדל של מערכת הקבצים:

@ מבחן חלל ציבורי givenPath_whenConvertsToAbsolutePath_thenCorrect () {Path p = Paths.get ("/ home / baeldung / articles.html"); נתיב absPath = p.toAbsolutePath (); assertEquals ("E: \ home \ baeldung \ articles.html", absPath.toString ()); }

עם זאת, כאשר הנתיב שיש לפתור מתגלה כבר מוחלט, השיטה מחזירה אותו כפי שהוא:

@ מבחן חלל ציבורי givenAbsolutePath_whenRetainsAsAbsolute_thenCorrect () {Path p = Paths.get ("E: \ home \ baeldung \ articles.html"); נתיב absPath = p.toAbsolutePath (); assertEquals ("E: \ home \ baeldung \ articles.html", absPath.toString ()); }

אנחנו יכולים גם להמיר כל נתיב למקבילו האמיתי על ידי קריאה ל toRealPath שיטה. שיטה זו מנסה לפתור את הנתיב על ידי מיפוי אלמנטים לספריות וקבצים בפועל במערכת הקבצים.

הגיע הזמן להשתמש במשתנה שיצרנו ב- להכין קטע המצביע על מיקום הבית המחובר של המשתמש במערכת הקבצים:

@Test הציבור בטל שניתןExistingPath_whenGetsRealPathToFile_thenCorrect () {Path p = Paths.get (HOME); נתיב realPath = p.toRealPath (); assertEquals (HOME, realPath.toString ()); }

הבדיקה שלעיל לא ממש מספרת לנו הרבה על התנהגות פעולה זו. התוצאה הברורה ביותר היא שאם הנתיב לא קיים במערכת הקבצים, אז הפעולה תזרוק IOException, תמשיך לקרוא.

בגלל היעדר דרך טובה יותר להסיע את הנקודה הזו הביתה, פשוט התבונן במבחן הבא, שמנסה להמיר נתיב שאינו קיים לדרך אמיתית:

@Test (צפוי = NoSuchFileException.class) חלל ציבורי givenInExistentPath_whenFailsToConvert_thenCorrect () {Path p = Paths.get ("E: \ home \ baeldung \ articles.html"); p.toRealPath (); }

המבחן מצליח כשאנחנו תופסים IOException. תת המעמד האמיתי של IOException שהמבצע הזה זורק הוא NoSuchFileException.

8. הצטרפות לנתיבים

ניתן להשיג הצטרפות לשני מסלולים באמצעות ה- לִפְתוֹר שיטה.

במילים פשוטות, אנחנו יכולים להתקשר ל לִפְתוֹר שיטה על כל אחד נָתִיב ולעבור בא דרך חלקית כטענה. נתיב חלקי זה מצורף לנתיב המקורי:

@ מבט בטל ציבורי givenTwoPaths_whenJoinsAndResolves_thenCorrect () {Path p = Paths.get ("/ baeldung / articles"); נתיב p2 = p.resolve ("java"); assertEquals ("\ baeldung \ articles \ java", p2.toString ()); }

עם זאת, כאשר מחרוזת הנתיב עברה אל ה- לִפְתוֹר השיטה אינה א דרך חלקית; בעיקר נתיב מוחלט ואז מוחזר הנתיב שהועבר:

@ מבחן הריק ציבורי givenAbsolutePath_whenResolutionRetainsIt_thenCorrect () {Path p = Paths.get ("/ baeldung / articles"); נתיב p2 = p.resolve ("C: \ baeldung \ מאמרים \ java"); assertEquals ("C: \ baeldung \ articles \ java", p2.toString ()); }

אותו דבר קורה בכל נתיב שיש בו אלמנט שורש. מחרוזת הנתיב "ג'אווה" אין רכיב שורש בעוד מחרוזת הנתיב "/ Java" בעל יסוד שורש. לכן, כאשר אתה עובר בנתיב עם אלמנט שורש, הוא מוחזר כמו שהוא:

@ מבחן חלל ציבורי givenPathWithRoot_whenResolutionRetainsIt_thenCorrect2 () {Path p = Paths.get ("/ baeldung / articles"); נתיב p2 = p.resolve ("/ java"); assertEquals ("\ java", p2.toString ()); }

9. מתייחס שבילים

התנאי מתייחסת פירושו פשוט ליצור נתיב ישיר בין שני נתיבים ידועים. למשל, אם יש לנו ספריה / ביילדונג ובתוכו יש לנו שתי ספריות נוספות כאלה / baeldung / מחברים ו / baeldung / מאמרים הם נתיבים תקפים.

הדרך אל מאמרים יחסי ל מחברים יתואר כ "העבר רמה אחת למעלה בהיררכיית הספריות ואז לספריית המאמרים" אוֹ .. \ מאמרים:

@Test ציבורי בטל givenSiblingPaths_whenCreatesPathToOther_thenCorrect () {Path p1 = Paths.get ("מאמרים"); נתיב p2 = Paths.get ("מחברים"); נתיב p1_rel_p2 = p1. מתייחס (p2); נתיב p2_rel_p1 = p2. להתייחס (p1); assertEquals (".. \ מחברים", p1_rel_p2.toString ()); assertEquals (".. \ מאמרים", p2_rel_p1.toString ()); }

בהנחה שאנחנו מזיזים את מאמרים מדריך ל מחברים תיקייה כזו שהם כבר לא אחים. פעולות ההתייחסות הבאות כוללות יצירת נתיב בין ביילדונג ו מאמרים ולהיפך:

@ מבחן הריק ציבורי givenNonSiblingPaths_whenCreatesPathToOther_thenCorrect () {Path p1 = Paths.get ("/ baeldung"); נתיב p2 = Paths.get ("/ baeldung / מחברים / מאמרים"); נתיב p1_rel_p2 = p1. מתייחס (p2); נתיב p2_rel_p1 = p2. להתייחס (p1); assertEquals ("מחברים \ מאמרים", p1_rel_p2.toString ()); assertEquals (".. \ ..", p2_rel_p1.toString ()); }

10. השוואת נתיבים

ה נָתִיב בכיתה יש יישום אינטואיטיבי של שווים שיטה המאפשרת לנו להשוות בין שני מסלולים לשוויון:

@Test הציבור בטל givenTwoPaths_whenTestsEquality_thenCorrect () {Path p1 = Paths.get ("/ baeldung / articles"); נתיב p2 = Paths.get ("/ baeldung / מאמרים"); נתיב p3 = Paths.get ("/ baeldung / מחברים"); assertTrue (p1.equals (p2)); assertFalse (p1.equals (p3)); }

אתה יכול גם לבדוק אם נתיב מתחיל במחרוזת נתונה:

@ מבחן חלל ציבורי givenPath_whenInspectsStart_thenCorrect () {Path p1 = Paths.get ("/ baeldung / articles"); assertTrue (p1.startsWith ("/ baeldung")); }

או מסתיים במחרוזת אחרת:

@ מבחן חלל ציבורי givenPath_whenInspectsEnd_thenCorrect () {Path p1 = Paths.get ("/ baeldung / articles"); assertTrue (p1.endsWith ("מאמרים")); }

11. מסקנה

במאמר זה, הצגנו פעולות נתיב ב- API של מערכת הקבצים החדשה (NIO2) שנשלחה כחלק מ- Java 7 וראינו את רובן בפעולה.

את דוגמאות הקוד המשמשות במאמר זה ניתן למצוא בפרויקט Github של המאמר.