רוכס ורוכסן בג'אווה

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

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

ספריות הליבה הללו הן חלק מה- java.util.zip חבילה - בה אנו יכולים למצוא את כל השירותים הקשורים לרוכסנות ולרוכסן.

2. מיקוד קובץ

בואו נסתכל תחילה על פעולה פשוטה - מיקוד קובץ יחיד.

לדוגמא שלנו כאן אנו נשלח קובץ בשם test1.txt לתוך ארכיון בשם compressed.zip.

כמובן שניגש לראשונה לקובץ מהדיסק - בואו נסתכל:

מחלקה ציבורית ZipFile {main static public void (String [] args) זורק IOException {String sourceFile = "test1.txt"; FileOutputStream fos = FileOutputStream חדש ("compressed.zip"); ZipOutputStream zipOut = ZipOutputStream חדש (fos); File fileToZip = קובץ חדש (sourceFile); FileInputStream fis = FileInputStream חדש (fileToZip); ZipEntry zipEntry = ZipEntry חדש (fileToZip.getName ()); zipOut.putNextEntry (zipEntry); בתים [] בתים = בתים חדשים [1024]; אורך int; בעוד ((אורך = fis.read (בתים))> = 0) {zipOut.write (בתים, 0, אורך); } zipOut.close (); fis.close (); fos.close (); }}

3. מיקוד קבצים מרובים

לאחר מכן, בואו נראה כיצד לרכוס מספר קבצים לקובץ zip אחד. נדחס test1.txt ו test2.txt לְתוֹך multiCompressed.zip:

מחלקה ציבורית ZipMultipleFiles {ציבורי ריק ריק סטריטי (מחרוזת [] טענות) זורק IOException {רשימה srcFiles = Arrays.asList ("test1.txt", "test2.txt"); FileOutputStream fos = FileOutputStream חדש ("multiCompressed.zip"); ZipOutputStream zipOut = ZipOutputStream חדש (fos); עבור (String srcFile: srcFiles) {File fileToZip = קובץ חדש (srcFile); FileInputStream fis = FileInputStream חדש (fileToZip); ZipEntry zipEntry = ZipEntry חדש (fileToZip.getName ()); zipOut.putNextEntry (zipEntry); בתים [] בתים = בתים חדשים [1024]; אורך int; בעוד ((אורך = fis.read (בתים))> = 0) {zipOut.write (בתים, 0, אורך); } fis.close (); } zipOut.close (); fos.close (); }}

4. מיקוד מדריך

עכשיו, בואו נדבר כיצד לרכוש ספרייה שלמה. אנו נספג zipTest לְתוֹך dirCompressed.zip :

מחלקה ציבורית ZipDirectory {public static void main (String [] args) זורק IOException {String sourceFile = "zipTest"; FileOutputStream fos = FileOutputStream חדש ("dirCompressed.zip"); ZipOutputStream zipOut = ZipOutputStream חדש (fos); File fileToZip = קובץ חדש (sourceFile); zipFile (fileToZip, fileToZip.getName (), zipOut); zipOut.close (); fos.close (); } פרטי ריק סטטי zipFile (File fileToZip, String fileName, ZipOutputStream zipOut) זורק IOException {if (fileToZip.isHidden ()) {return; } אם (fileToZip.isDirectory ()) {if (fileName.endsWith ("/")) {zipOut.putNextEntry (חדש ZipEntry (fileName)); zipOut.closeEntry (); } אחר {zipOut.putNextEntry (חדש ZipEntry (fileName + "/")); zipOut.closeEntry (); } קובץ [] ילדים = fileToZip.listFiles (); עבור (File childFile: children) {zipFile (childFile, fileName + "/" + childFile.getName (), zipOut); } לחזור; } FileInputStream fis = FileInputStream חדש (fileToZip); ZipEntry zipEntry = ZipEntry חדש (fileName); zipOut.putNextEntry (zipEntry); בתים [] בתים = בתים חדשים [1024]; אורך int; בעוד ((אורך = fis.read (בתים))> = 0) {zipOut.write (בתים, 0, אורך); } fis.close (); }}

ציין זאת:

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

5. לפתוח ארכיון

בואו כעת לפתוח ארכיון ולחלץ את תוכנו.

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

בוא נראה:

מחלקה ציבורית UnzipFile {public static void main (String [] args) זורק IOException {String fileZip = "src / main / resources / unzipTest / compressed.zip"; קובץ destDir = קובץ חדש ("src / main / resources / unzipTest"); בתא [] חיץ = בית חדש [1024]; ZipInputStream zis = חדש ZipInputStream (FileInputStream חדש (fileZip)); ZipEntry zipEntry = zis.getNextEntry (); בעוד (zipEntry! = null) {// ...} zis.closeEntry (); zis.close (); }}

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

בעוד (zipEntry! = null) {File newFile = newFile (destDir, zipEntry); אם (zipEntry.isDirectory ()) {if (! newFile.isDirectory () &&! newFile.mkdirs ()) {זרוק IOException חדש ("נכשל יצירת הספרייה" + newFile); }} אחר {/ / fix עבור ארכיונים שנוצרו על ידי Windows File File = newFile.getParentFile (); אם (! parent.isDirectory () &&! parent.mkdirs ()) {זרוק IOException חדש ("נכשל יצירת הספרייה" + הורה); } // כתוב תוכן קובץ FileOutputStream fos = FileOutputStream חדש (newFile); int len; בעוד ((len = zis.read (חיץ))> 0) {fos.write (חיץ, 0, len); } fos.close (); } zipEntry = zis.getNextEntry (); }

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

נקודת מפתח נוספת ניתן לראות ב קובץ חדש() שיטה:

קובץ סטטי ציבורי newFile (File destinationDir, ZipEntry zipEntry) זורק IOException {File destFile = קובץ חדש (destinationDir, zipEntry.getName ()); מחרוזת destDirPath = destinationDir.getCanonicalPath (); מחרוזת destFilePath = destFile.getCanonicalPath (); אם (! destFilePath.startsWith (destDirPath + File.separator)) {לזרוק IOException חדש ("הכניסה היא מחוץ ליעד היעד:" + zipEntry.getName ()); } להחזיר destFile; }

שיטה זו שומרת מפני כתיבת קבצים למערכת הקבצים מחוץ לתיקיית היעד. נקודת תורפה זו נקראת Zip Slip ותוכל לקרוא עליה עוד כאן.

6. מסקנה

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

ניתן למצוא את היישום של דוגמאות אלה ב- GitHub.