מבוא ל- Java NIO2 File API

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

במאמר זה אנו נתמקד בממשקי ה- I / O החדשים בפלטפורמת Java - NIO2 - לעשות מניפולציה בסיסית של קבצים.

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

2. התקנה

הגדרת הפרויקט שלך לשימוש ב- APIs של קבצים היא רק עניין של ייבוא ​​זה:

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

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

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

ה קבצים class היא אחת מנקודות הכניסה העיקריות של java.nio.file חֲבִילָה. מחלקה זו מציעה קבוצה עשירה של ממשקי API לקריאה, כתיבה וניהול קבצים וספריות. ה קבצים שיטות כיתה עובדות על מקרים של נָתִיב חפצים.

3. בדיקת קובץ או ספריה

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

למען הפשטות, בכל פעם שאנחנו משתמשים במונח קוֹבֶץאנו מתייחסים לקבצים ולספריות, אלא אם כן צוין אחרת במפורש.

כדי לבדוק אם קיים קובץ, אנו משתמשים ב- קיים ממשק API:

@Test ציבורי בטל שניתןExistentPath_whenConfirmsFileExists_thenCorrect () {Path p = Paths.get (HOME); assertTrue (Files.exists (p)); }

כדי לבדוק שקובץ לא קיים, אנו משתמשים ב- לא קיים ממשק API:

@ מבחן הריק ציבורי givenNonexistentPath_whenConfirmsFileNotExists_thenCorrect () {Path p = Paths.get (HOME + "/inexistent_file.txt"); assertTrue (Files.notExists (p)); }

אנחנו יכולים גם לבדוק אם קובץ הוא קובץ רגיל כמו myfile.txt או שהוא רק ספריה, אנו משתמשים ב- isRegularFile ממשק API:

@Test הציבור בטל givenDirPath_whenConfirmsNotRegularFile_thenCorrect () {נתיב p = Paths.get (HOME); assertFalse (Files.isRegularFile (p)); }

ישנן גם שיטות סטטיות לבדיקת הרשאות קבצים. כדי לבדוק אם ניתן לקרוא קובץ, אנו משתמשים ב- הוא קריא ממשק API:

@Test הציבור בטל שניתןExistentDirPath_whenConfirmsReadable_thenCorrect () {Path p = Paths.get (HOME); assertTrue (Files.isReadable (p)); }

כדי לבדוק אם הוא ניתן לכתיבה, אנו משתמשים ב- isWritable ממשק API:

@Test ציבורי בטל שניתןExistentDirPath_whenConfirmsWritable_thenCorrect () {Path p = Paths.get (HOME); assertTrue (Files.isWritable (p)); }

באופן דומה, כדי לבדוק אם ניתן להפעיל אותו:

@Test הציבורי בטל שניתןExistentDirPath_whenConfirmsExecutable_thenCorrect () {Path p = Paths.get (HOME); assertTrue (Files.isExecutable (p)); }

כשיש לנו שני נתיבים, אנו יכולים לבדוק אם שניהם מפנים לאותו קובץ במערכת הקבצים הבסיסית:

@Test ציבורי בטל givenSameFilePaths_whenConfirmsIsSame_thenCorrect () {נתיב p1 = Paths.get (HOME); נתיב p2 = Paths.get (HOME); assertTrue (Files.isSameFile (p1, p2)); }

4. יצירת קבצים

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

כל רכיבי השם בנתיב חייבים להתקיים, מלבד שם הקובץ, אחרת נקבל חריג IO:

@Test ציבורי בטל givenFilePath_whenCreatesNewFile_thenCorrect () {String fileName = "myfile_" + UUID.randomUUID (). ToString () + ".txt"; נתיב p = Paths.get (HOME + "/" + fileName); assertFalse (Files.exists (p)); Files.createFile (p); assertTrue (Files.exists (p)); }

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

כדי ליצור ספריה, אנו משתמשים ב- ליצור תיקייה ממשק API:

@Test public void givenDirPath_whenCreatesNewDir_thenCorrect () {String dirName = "myDir_" + UUID.randomUUID (). ToString (); נתיב p = Paths.get (HOME + "/" + dirName); assertFalse (Files.exists (p)); Files.createDirectory (p); assertTrue (Files.exists (p)); assertFalse (Files.isRegularFile (p)); assertTrue (Files.isDirectory (p)); }

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

@Test (צפוי = NoSuchFileException.class) חלל ציבורי givenDirPath_whenFailsToCreateRecursively_thenCorrect () {String dirName = "myDir_" + UUID.randomUUID (). ToString () + "/ sub sub"; נתיב p = Paths.get (HOME + "/" + dirName); assertFalse (Files.exists (p)); Files.createDirectory (p); }

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

@ מבחן הריק ציבורי givenDirPath_whenCreatesRecursively_thenCorrect () {Path dir = Paths.get (HOME + "/ myDir_" + UUID.randomUUID (). ToString ()); נתיב תת-תיקון = dir.resolve ("תת-תיקון"); assertFalse (Files.exists (dir)); assertFalse (Files.exists (subdir)); Files.createDirectories (תת-תיקיה); assertTrue (Files.exists (dir)); assertTrue (Files.exists (subdir)); }

5. יצירת קבצים זמניים

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

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

@Test הציבור בטל givenFilePath_whenCreatesTempFile_thenCorrect () {קידומת מחרוזת = "log_"; סיומת מחרוזת = ".txt"; נתיב p = Paths.get (HOME + "/"); Files.createTempFile (p, קידומת, סיומת); assertTrue (Files.exists (p)); }

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

המבחן הנ"ל יוצר קובץ זמני ב- בית ספרייה, ממתינים מראש ומוסיפים את מחרוזות הקידומת והסיומת שסופקו בהתאמה. בסופו של דבר נקרא שם קובץ כמו log_8821081429012075286.txt. המחרוזת המספרית הארוכה נוצרת על ידי המערכת.

עם זאת, אם לא נספק קידומת וסיומת, שם הקובץ יכלול רק את המחרוזת המספרית הארוכה ואת ברירת המחדל .tmp סיומת:

@Test ציבורי בטל givenPath_whenCreatesTempFileWithDefaults_thenCorrect () {Path p = Paths.get (HOME + "/"); Files.createTempFile (p, null, null); assertTrue (Files.exists (p)); }

הפעולה שלעיל יוצרת קובץ עם שם כמו 8600179353689423985.tmp.

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

@Test הציבור בטל givenNoFilePath_whenCreatesTempFileInTempDir_thenCorrect () {נתיב p = Files.createTempFile (null, null); assertTrue (Files.exists (p)); }

ב- Windows, ברירת המחדל תהיה משהו כמו C: \ Users \ user \ AppData \ Local \ Temp \ 6100927974988978748.tmp.

ניתן להתאים את כל הפעולות הנ"ל ליצירת ספריות ולא קבצים רגילים באמצעות createTempDirectory במקום createTempFile.

6. מחיקת קובץ

כדי למחוק קובץ, אנו משתמשים ב- לִמְחוֹק ממשק API. לצורך הבהרה, הבדיקה הבאה מבטיחה תחילה שהקובץ לא קיים, ואז יוצרת אותו ומאשרת שהוא קיים ולבסוף מוחקת אותו ומאשרת שהוא כבר לא קיים:

@ מבחן חלל ציבורי givenPath_whenDeletes_thenCorrect () {Path p = Paths.get (HOME + "/fileToDelete.txt"); assertFalse (Files.exists (p)); Files.createFile (p); assertTrue (Files.exists (p)); Files.delete (p); assertFalse (Files.exists (p)); }

עם זאת, אם קובץ לא קיים במערכת הקבצים, פעולת המחיקה תיכשל עם IOException:

@Test (צפוי = NoSuchFileException.class) חלל ציבורי givenInexistentFile_whenDeleteFails_thenCorrect () {Path p = Paths.get (HOME + "/inexistentFile.txt"); assertFalse (Files.exists (p)); Files.delete (p); }

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

@Test ציבורי בטל givenInexistentFile_whenDeleteIfExistsWorks_thenCorrect () {Path p = Paths.get (HOME + "/inexistentFile.txt"); assertFalse (Files.exists (p)); Files.deleteIfExists (p); }

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

@Test (צפוי = DirectoryNotEmptyException.class) חלל ציבורי givenPath_whenFailsToDeleteNonEmptyDir_thenCorrect () {Path dir = Paths.get (HOME + "/ emptyDir" + UUID.randomUUID (). ToString ()); Files.createDirectory (דיר); assertTrue (Files.exists (dir)); קובץ נתיב = dir.resolve ("file.txt"); Files.createFile (קובץ); Files.delete (דיר); assertTrue (Files.exists (dir)); }

7. העתקת קבצים

באפשרותך להעתיק קובץ או ספריה באמצעות עותק ממשק API:

@Test הציבור בטל givenFilePath_whenCopiesToNewLocation_thenCorrect () {Path dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); נתיב dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); נתיב file1 = dir1.resolve ("filetocopy.txt"); נתיב file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (file1); assertTrue (Files.exists (file1)); assertFalse (Files.exists (file2)); Files.copy (file1, file2); assertTrue (Files.exists (file2)); }

ההעתקה נכשלה אם קובץ היעד קיים אלא אם כן REPLACE_EXISTING אפשרות זו מוגדרת:

@Test (צפוי = FileAlreadyExistsException.class) חלל ציבורי givenPath_whenCopyFailsDueToExistingFile_thenCorrect () {Path dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); נתיב dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); נתיב file1 = dir1.resolve ("filetocopy.txt"); נתיב file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (file1); Files.createFile (file2); assertTrue (Files.exists (file1)); assertTrue (Files.exists (file2)); Files.copy (file1, file2); Files.copy (file1, file2, StandardCopyOption.REPLACE_EXISTING); }

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

8. העברת קבצים

באפשרותך להעביר קובץ או ספריה באמצעות מהלך \ לזוז \ לעבור ממשק API. זה דומה ברוב המובנים ל עותק מבצע. אם פעולת ההעתקה מקבילה לא העתקה והדבקה פעולה במערכות מבוססות GUI, אם כן מהלך \ לזוז \ לעבור מקביל ל- a חתוך והדבק מבצע:

@Test ציבורי בטל givenFilePath_whenMovesToNewLocation_thenCorrect () {Path dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); נתיב dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); נתיב file1 = dir1.resolve ("filetocopy.txt"); נתיב file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (file1); assertTrue (Files.exists (file1)); assertFalse (Files.exists (file2)); Files.move (file1, file2); assertTrue (Files.exists (file2)); assertFalse (Files.exists (file1)); }

ה מהלך \ לזוז \ לעבור הפעולה נכשלת אם קובץ היעד קיים אלא אם כן REPLACE_EXISTING אפשרות מוגדרת בדיוק כמו שעשינו עם עותק מבצע:

@Test (צפוי = FileAlreadyExistsException.class) חלל ציבורי givenFilePath_whenMoveFailsDueToExistingFile_thenCorrect () {Path dir1 = Paths.get (HOME + "/ firstdir_" + UUID.randomUUID (). ToString ()); נתיב dir2 = Paths.get (HOME + "/ otherdir_" + UUID.randomUUID (). ToString ()); Files.createDirectory (dir1); Files.createDirectory (dir2); נתיב file1 = dir1.resolve ("filetocopy.txt"); נתיב file2 = dir2.resolve ("filetocopy.txt"); Files.createFile (file1); Files.createFile (file2); assertTrue (Files.exists (file1)); assertTrue (Files.exists (file2)); Files.move (file1, file2); Files.move (file1, file2, StandardCopyOption.REPLACE_EXISTING); assertTrue (Files.exists (file2)); assertFalse (Files.exists (file1)); }

9. מסקנה

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

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