מדריך קלט / פלט בגרובי

1. הקדמה

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

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

במידת הצורך, נקשר למאמרי Java הרלוונטיים שלנו לצורך השוואה קלה למקבילה של Java.

2. קריאת קבצים

Groovy מוסיף פונקציונליות נוחה לקריאת קבצים בצורה של כל שורה שיטות, שיטות לקבל BufferedReaders ו- InputStreams, ודרכים להשיג את כל נתוני הקבצים עם שורת קוד אחת.

ל- Java 7 ו- Java 8 יש תמיכה דומה בקריאת קבצים ב- Java.

2.1. קורא עם כל שורה

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

def lines = [] קובץ חדש ('src / main / resources / ioInput.txt'). eachLine {line -> lines.add (line)}

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

def lineNoRange = 2..4 def lines = [] קובץ חדש ('src / main / resources / ioInput.txt'). eachLine {line, lineNo -> if (lineNoRange.contains (lineNo)) {lines.add (line )}}

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

בואו נתחיל את מספרי השורות שלנו באפס:

קובץ חדש ('src / main / resources / ioInput.txt'). eachLine (0, {line, lineNo -> if (lineNoRange.contains (lineNo)) {lines.add (line)}})

אם נזרק חריג כל שורה, גרובי מוודא שמשאב הקבצים ייסגר. ממש כמו א נסה עם משאבים או א נסה סוף סוף בג'אווה.

2.2. קריאה עם Reader

אנחנו יכולים גם להשיג בקלות BufferedReader מגרובי קוֹבֶץ לְהִתְנַגֵד. אנחנו יכולים להשתמש withReader לקבל BufferedReader לאובייקט הקובץ ולהעביר אותו לסגירה:

def actualCount = 0 קובץ חדש ('src / main / resources / ioInput.txt'). withReader {reader -> while (reader.readLine ()) {actualCount ++}}

כמו עם כל שורה, ה withReader השיטה תסגור אוטומטית את המשאב כאשר יוצא חריג.

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

def outputPath = 'src / main / resources / ioOut.txt' קורא def = קובץ חדש ('src / main / resources / ioInput.txt'). newReader () קובץ חדש (outputPath) .append (reader) reader.close ( )

בניגוד לשיטות האחרות שבחנו עד כה, אנחנו אחראים לסגירת ה- BufferedReader משאב כאשר אנו רוכשים א שנאגרוקוֹרֵא בדרך זו.

2.3. קורא עם InputStreamס

דומה ל withReader ו newReader, Groovy מספק גם שיטות לעבודה קלה עם InputStreamס. למרות שאנחנו יכולים לקרוא טקסט עם InputStreams ו- Groovy אפילו מוסיפים פונקציונליות לכך, InputStreams משמשים לרוב לנתונים בינאריים.

בואו נשתמש עם InputStream להעביר InputStream לסגירה וקרא בתאים:

בתים [] נתונים = [] קובץ חדש ("src / main / resources / binaryExample.jpg"). עם InputStream {stream -> data = stream.getBytes ()}

אם אנחנו צריכים לקבל את InputStream נוכל להשיג אחד באמצעות newInputStream:

def outputPath = 'src / main / resources / binaryOut.jpg' def is = קובץ חדש ('src / main / resources / binaryExample.jpg'). newInputStream () קובץ חדש (outputPath) .append (is) is.close ( )

כמו עם BufferedReader, אנחנו צריכים לסגור את שלנו InputStream משאבים את עצמנו כשאנחנו משתמשים newInputStream, אך לא בשימוש עם InputStream.

2.4. קריאת דרכים אחרות

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

אם אנחנו רוצים את שורות הקובץ שלנו ב- רשימה, אנחנו יכולים להשתמש לאסוף עם איטרטור זה עבר לסגירה:

def actualList = קובץ חדש ('src / main / resources / ioInput.txt'). אסוף את {it}

כדי להכניס את שורות הקובץ למערך של מיתרים, אנחנו יכולים להשתמש כמחרוזת []:

def actualArray = קובץ חדש ('src / main / resources / ioInput.txt') כמחרוזת []

עבור קבצים קצרים, אנו יכולים לקבל את כל התוכן ב- חוּט באמצעות טֶקסט:

def actualString = קובץ חדש ('src / main / resources / ioInput.txt'). טקסט

וכשעובדים עם קבצים בינאריים, יש את בתים שיטה:

def indhold = קובץ חדש ('src / main / resources / binaryExample.jpg'). בתים

3. כתיבת קבצים

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

def outputLines = ['קו אחד של דוגמת פלט', 'קו שתיים של דוגמת פלט', 'קו שלוש של דוגמת פלט']

3.1. כותב עם סופר

כמו בקריאת קובץ, אנחנו יכולים גם להשיג בקלות BufferedWriter מתוך א קוֹבֶץ לְהִתְנַגֵד.

בואו נשתמש withWriter לקבל BufferedWriter ולהעביר אותו לסגירה:

def outputFileName = 'src / main / resources / ioOutput.txt' קובץ חדש (outputFileName). withWriter {כותב -> outputLines.each {שורה -> שורה שורה.כתיבה}}

באמצעות withReader יסגור את המשאב במקרה של חריג.

ל- Groovy יש גם שיטה להשיג את BufferedWriter לְהִתְנַגֵד. בוא נקבל BufferedWriter באמצעות newWriter:

def outputFileName = 'src / main / resources / ioOutput.txt' def writer = קובץ חדש (outputFileName) .newWriter () outputLines.forEach {line -> writer.writeLine line} writer.flush () writer.close ()

אנחנו אחראים על שטיפה וסגירה BufferedWriter להתנגד כאשר אנו משתמשים newWriter.

3.2. כתיבה עם זרמי פלט

אם אנו כותבים נתונים בינאריים, אנחנו יכולים להשיג OutputStream באמצעות אחד מהם withOutputStream אוֹ newOutputStream.

בוא נכתוב כמה בתים לקובץ באמצעות withOutputStream:

בתים [] outBytes = [44, 88, 22] קובץ חדש (outputFileName). withOutputStream {stream -> stream.write (outBytes)}

בואו נקבל OutputStream התנגד עם newOutputStream והשתמש בו כדי לכתוב כמה בתים:

בתים [] outBytes = [44, 88, 22] def os = קובץ חדש (outputFileName) .newOutputStream () os.write (outBytes) os.close ()

דומה ל InputStream, BufferedReader, ו BufferedWriterאנחנו אחראים לסגירת ה- OutputStream את עצמנו כשאנחנו משתמשים newOutputStream.

3.3. כותב עם << המפעיל

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

בואו נשתמש ב- << המפעיל לכתוב כמה שורות טקסט פשוטות:

def ln = System.getProperty ('line.separator') def outputFileName = 'src / main / resources / ioOutput.txt' קובץ חדש (outputFileName) << "שורה אחת של דוגמת הפלט $ {ln}" + "שורה שנייה של דוגמת פלט $ {ln} שורה שלוש מדוגמת פלט "

3.4. כתיבת נתונים בינאריים עם בתים

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

בואו נכתוב נתונים בינאריים באותה דרך:

def outputFileName = 'src / main / resources / ioBinaryOutput.bin' def outputFile = קובץ חדש (outputFileName) בתים [] outBytes = [44, 88, 22] outputFile.bytes = outBytes

4. חוצה עצים של קבצים

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

4.1. רישום קבצים עם כל קובץ

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

קובץ חדש ('src / main / resources'). eachFile {file -> println file.name}

תרחיש נפוץ נוסף בעבודה עם קבצים הוא הצורך לסנן את הקבצים על פי שם הקובץ. בואו לרשום רק את הקבצים שמתחילים ב- "io" ומסתיימים ב- ".txt" באמצעות eachFileMatch וביטוי קבוע:

קובץ חדש ('src / main / resources'). eachFileMatch (~ / io. * \. txt /) {file -> println file.name}

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

בואו לרשום רקורסיבית את כל הקבצים באמצעות eachFileRecurse ולספק לו א סוג קובץ שֶׁל קבצים:

קובץ חדש ('src / main'). eachFileRecurse (FileType.FILES) {file -> println "$ file.parent $ file.name"}

ה כל קובץ שיטות לזרוק IllegalArgumentException אם אנו מספקים להם נתיב לקובץ במקום לספריה.

גרובי מספקת גם את eachDir שיטות לעבודה עם ספריות בלבד. אנחנו יכולים להשתמש eachDir ואת הגרסאות שלה כדי להשיג את אותו הדבר כמו השימוש כל קובץ עם סוג קובץ שֶׁל ספריות.

בואו ברשימה רקורטיבית ספריות עם eachFileRecurse:

קובץ חדש ('src / main'). eachFileRecurse (FileType.DIRECTORIES) {file -> println "$ file.parent $ file.name"}

עכשיו, בואו נעשה את אותו הדבר עם eachDirRecurse:

קובץ חדש ('src / main'). eachDirRecurse {dir -> println "$ dir.parent $ dir.name"}

4.2. רישום קבצים עם Traverse

למקרי שימוש מורכבים יותר במעבר בספריות, אנו יכולים להשתמש ב- לַחֲצוֹת שיטה. זה מתפקד באופן דומה ל eachFileRecurse אך מספק את היכולת לחזור FileVisitResult אובייקטים לשלוט בעיבוד.

בואו נשתמש לַחֲצוֹת על שלנו src / main ספריה ודלג על עיבוד העץ מתחת ל- קִצבִּי מַדרִיך:

קובץ חדש ('src / main'). חוצה {file -> if (file.directory && file.name == 'groovy') {FileVisitResult.SKIP_SUBTREE} אחר {println "$ file.parent - $ file.name"} }

5. עבודה עם נתונים ואובייקטים

5.1. סדרת פרימיטיבים

בג'אווה נוכל להשתמש DataInputStream ו DataOutputStream לסידור שדות נתונים פרימיטיביים. גרובי מוסיף גם כאן הרחבות שימושיות.

בואו נגדיר כמה נתונים פרימיטיביים:

הודעת מחרוזת = 'זהו מחרוזת סדרתית' int length = message.length () בוליאני valid = true

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

קובץ חדש ('src / main / resources / ioData.txt'). withDataOutputStream {out -> out.writeUTF (message) out.writeInt (length) out.writeBoolean (valid)}

וקרא אותו שוב בשימוש withDataInputStream:

String loadedMessage = "" int loadedLength boolean loadedValid new file ('src / main / resources / ioData.txt'). WithDataInputStream {is -> loadedMessage = is.readUTF () loadedLength = is.readInt () loadedValid = is.readBoolean ( )}

דומה לאחר עם* שיטות, withDataOutputStream ו withDataInputStream העבירו את הזרם לסגירה וודאו שהוא סגור כראוי.

5.2. סידור אובייקטים

גרובי מתבסס גם על Java ObjectInputStream ו ObjectOutputStream כדי לאפשר לנו לסדר בקלות אובייקטים שמיישמים ניתן לבצע סדרתי.

בואו נגדיר תחילה מחלקה שמיישמת ניתן לבצע סדרתי:

מחלקה משימות משימות ניתן לסידור {תיאור מחרוזת תאריך התחלה תאריך תאריך בשל תאריך מצב

עכשיו בואו ניצור מופע של מְשִׁימָה שנוכל לסדר לקובץ:

משימת משימה = משימה חדשה (תיאור: 'הוצא את האשפה', startDate: תאריך חדש (), סטטוס: 0)

עם שלנו מְשִׁימָה אובייקט ביד, בואו לסדר אותו לקובץ באמצעות withObjectOutputStream:

קובץ חדש ('src / main / resources / ioSerializedObject.txt'). withObjectOutputStream {out -> out.writeObject (task)}

לבסוף, בואו לקרוא את שלנו מְשִׁימָה חזרה לשימוש withObjectInputStream:

משימת משימה קראו קובץ חדש ('src / main / resources / ioSerializedObject.txt'). WithObjectInputStream {is -> taskRead = is.readObject ()}

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

6. מסקנה

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

נגענו רק בכמה משיטות העוזר, לכן כדאי לחפור בתיעוד של גרובי כדי לראות מה עוד זה מוסיף לפונקציונליות ה- I / O של Java.

קוד הדוגמה זמין ב- GitHub.