כיצד לנעול קובץ ב- Java

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

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

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

2. מבוא למנעולי קבצים

באופן כללי, ישנם שני סוגים של מנעולים:

    • מנעולים בלעדיים - מכונים גם מנעולי כתיבה
    • מנעולים משותפים - מכונים גם מנעולי קריאה

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

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

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

3. מנעולי קבצים ב- Java

ספריית Java NIO מאפשרת נעילת קבצים ברמת מערכת ההפעלה. ה לנעול() ו tryLock () שיטות של א FileChannel הם למטרה זו.

אנחנו יכולים ליצור FileChannel דרך א FileInputStream, א FileOutputStream, או א RandomAccessFile. לשלושתם יש getChannel () שיטה המחזירה א FileChannel.

לחלופין, אנו יכולים ליצור FileChannel ישירות דרך הסטטי לִפְתוֹחַ שיטה:

נסה (ערוץ FileChannel = FileChannel.open (נתיב, openOptions)) {// כתוב לערוץ}

לאחר מכן, נבדוק אפשרויות שונות לקבלת נעילות בלעדיות ומשותפות ב- Java. למידע נוסף על ערוצי קבצים, עיין במדריך שלנו ל- Java FileChannel.

4. מנעולים בלעדיים

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

אנו מקבלים מנעולים בלעדיים על ידי התקשרות לנעול() אוֹ tryLock () על FileChannel מעמד. אנו יכולים גם להשתמש בשיטות העמוסות שלהם:

  • נעילה (מיקום ארוך, גודל ארוך, בוליאני משותף)
  • tryLock (מיקום ארוך, גודל ארוך, בוליאני משותף)

במקרים אלה, מְשׁוּתָף יש להגדיר את הפרמטר שֶׁקֶר.

כדי לקבל נעילה בלעדית, עלינו להשתמש בכתב FileChannel. אנחנו יכולים ליצור את זה דרך getChannel () שיטות של א FileOutputStream או א RandomAccessFile. לחלופין, כפי שצוין לעיל, אנו יכולים להשתמש בסטטי לִפְתוֹחַ שיטת ה- FileChannel מעמד. כל מה שאנחנו צריכים זה להגדיר את הטיעון השני StandardOpenOption.APPEND:

נסה (FileChannel channel = FileChannel.open (path, StandardOpenOption.APPEND)) {// כתוב לערוץ}

4.1. מנעולים בלעדיים באמצעות FileOutputStream

א FileChannel נוצר מ- FileOutputStream ניתן לכתיבה. אנו יכולים אפוא לרכוש מנעול בלעדי:

נסה (FileOutputStream fileOutputStream = FileOutputStream חדש ("/ tmp / testfile.txt"); FileChannel channel = fileOutputStream.getChannel (); FileLock lock = channel.lock ()) {// כתוב לערוץ}

פה, channel.lock () או שייחסם עד שהוא ישיג נעילה, או שהוא ישליך חריג. לדוגמא, אם האזור שצוין כבר נעול, OverlappingFileLockException נזרק. ראה את Javadoc עבור רשימה מלאה של חריגים אפשריים.

אנו יכולים גם לבצע נעילה שאינה חוסמת באמצעות channel.tryLock (). אם היא לא מצליחה להשיג נעילה מכיוון שתוכנית אחרת מחזיקה תוכנית חופפת, היא חוזרת ריק. אם היא לא מצליחה לעשות זאת מסיבה אחרת, אזי יוצא מן הכלל חריג מתאים.

4.2. מנעולים בלעדיים באמצעות RandomAccessFile

עם RandomAccessFile, עלינו להציב דגלים על הפרמטר השני של הבנאי.

כאן נפתח את הקובץ עם הרשאות קריאה וכתיבה:

נסה (קובץ RandomAccessFile = RandomAccessFile חדש ("/ tmp / testfile.txt", "rw"); FileChannel channel = file.getChannel (); FileLock lock = channel.lock ()) {// כתוב לערוץ} 

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

4.3. מנעולים בלעדיים דורשים כתוב FileChannel

כאמור, מנעולים בלעדיים זקוקים לערוץ הניתן לכתב. לכן, איננו יכולים להשיג נעילה בלעדית באמצעות א FileChannel נוצר מ- FileInputStream:

נתיב נתיב = Files.createTempFile ("foo", "txt"); יומן לוגר = LoggerFactory.getLogger (this.getClass ()); נסה (FileInputStream fis = FileInputStream חדש (path.toFile ()); FileLock lock = fis.getChannel (). lock ()) {// unreachable code} לתפוס (NonWritableChannelException e) {// חריג ידית}

בדוגמה לעיל, לנעול() השיטה תזרוק א NonWritableChannelException. אכן, זה בגלל שאנחנו קוראים getChannel על FileInputStream, שיוצר ערוץ לקריאה בלבד.

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

5. מנעולים משותפים

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

כמו FileChannel ניתן להשיג בטלפון getChannel () שיטה על א FileInputStream או א RandomAccessFile. שוב, אפשרות אחרת היא להשתמש בסטטי לִפְתוֹחַ שיטת ה- FileChannel מעמד. במקרה כזה, הגדרנו את הטיעון השני StandardOpenOption.READ:

נסה (FileChannel channel = FileChannel.open (path, StandardOpenOption.READ); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// קרא מהערוץ}

דבר אחד שיש לציין כאן הוא שבחרנו לנעול את כל הקובץ על ידי התקשרות נעילה (0, Long.MAX_VALUE, נכון). יכולנו גם לנעול רק אזור מסוים בקובץ על ידי שינוי שני הפרמטרים הראשונים לערכים שונים. יש להגדיר את הפרמטר השלישי נָכוֹן במקרה של מנעול משותף.

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

5.1. מנעולים משותפים באמצעות FileInputStream

א FileChannel שהושג מא FileInputStream הוא קריא. אנו יכולים אפוא להשיג נעילה משותפת:

נסה (FileInputStream fileInputStream = FileInputStream חדש ("/ tmp / testfile.txt"); FileChannel channel = fileInputStream.getChannel (); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// קרא מהערוץ }

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

5.2. מנעולים משותפים באמצעות RandomAccessFile

הפעם נוכל לפתוח את הקובץ רק באמצעות לקרוא הרשאות:

נסה (קובץ RandomAccessFile = חדש RandomAccessFile ("/ tmp / testfile.txt", "r"); FileChannel channel = file.getChannel (); FileLock lock = channel.lock (0, Long.MAX_VALUE, true)) {// קרא מהערוץ}

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

5.3. מנעולים משותפים דורשים קריאה FileChannel

מסיבה זו, איננו יכולים לרכוש נעילה משותפת באמצעות FileChannel נוצר מ- FileOutputStream:

נתיב נתיב = Files.createTempFile ("foo", "txt"); נסה (FileOutputStream fis = FileOutputStream חדש (path.toFile ()); FileLock נעילה = fis.getChannel (). נעילה (0, Long.MAX_VALUE, נכון)) {// קוד בלתי נגיש} לתפוס (NonWritableChannelException e) {// ידית יוצא מן הכלל } 

בדוגמה זו, הקריאה ל לנעול() מנסה להשיג נעילה משותפת בערוץ שנוצר מ- FileOutputStream. ערוץ כזה הוא כתיבה בלבד. זה לא ממלא את הצורך שהערוץ צריך להיות קריא. זה יפעיל a NonWritableChannelException.

שוב, קטע זה הוא רק כדי להדגים שאיננו יכולים לקרוא מערוץ שאינו קריא.

6. דברים שיש לקחת בחשבון

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

במערכות POSIX מנעולים מייעצים. תהליכים שונים שקוראים או כותבים לקובץ נתון חייבים להסכים על פרוטוקול נעילה. זה יבטיח את שלמות הקובץ. מערכת ההפעלה עצמה לא תאכוף נעילה כלשהי.

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

7. מסקנה

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

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

כמו תמיד, קוד המקור לדוגמאות זמין ב- GitHub.


$config[zx-auto] not found$config[zx-overlay] not found