"היי! בשיעור של היום, נמשיך בשיחתנו על זרמי קלט ופלט ב-Java ( Java I/O ). זה לא השיעור הראשון בנושא זה, ובוודאי לא יהיה האחרון :)
שכן קורה, שפת Java מספקת דרכים רבות לעבוד עם I/O. יש לא מעט מחלקות שמיישמות את הפונקציונליות הזו, אז חילקנו אותן למספר שיעורים - כדי שלא תתבלבלו מההתחלה :) בעבר נגענו בשיעורים
הנה איך זה נראה לקרוא נתונים מקובץ באמצעות
שכן קורה, שפת Java מספקת דרכים רבות לעבוד עם I/O. יש לא מעט מחלקות שמיישמות את הפונקציונליות הזו, אז חילקנו אותן למספר שיעורים - כדי שלא תתבלבלו מההתחלה :) בעבר נגענו בשיעורים BufferedReader, כמו גם בכיתות InputStreamהמופשטות OutputStreamובכמה צאצאים. היום נשקול 3 כיתות חדשות: FileInputStream, FileOutputStream, ו BufferedInputStream.
המחלקה FileOutputStream
המטרה העיקרית שלFileOutputStreamהמחלקה היא לכתוב בייטים לקובץ. שום דבר מסובך :) FileOutputStreamהוא אחד המימושים של OutputStreamהמחלקה המופשטת. בבנאי, אובייקטים של מחלקה זו לוקחים את הנתיב לקובץ היעד (שם יש לכתוב את הבתים) או אובייקט File. נבחן דוגמאות של כל אחד מהם:
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
} בעת יצירת Fileהאובייקט העברנו את הנתיב הרצוי לבנאי. אנחנו לא צריכים ליצור אותו מראש: אם הוא לא קיים, התוכנית תיצור אותו. אתה יכול גם להסתדר בלי ליצור אובייקט נוסף, פשוט להעביר מחרוזת עם הנתיב:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
} התוצאה בשני המקרים תהיה זהה. אנחנו יכולים לפתוח את הקובץ שלנו ולראות שם את הדברים הבאים:
Hi! Welcome to CodeGym — The best site for would-be programmers! אבל יש כאן ניואנס אחד. נסה להריץ את הקוד מהדוגמה למעלה מספר פעמים ברציפות. לאחר מכן עיין בקובץ וענה על השאלה הזו: כמה שורות יש לו? רק אחד. אבל הרצת את הקוד כמה פעמים. מסתבר שהנתונים מוחלפים בכל פעם - הישן מוחלף בחדש. מה עושים אם זה לא מתאים לנו ואנחנו צריכים לכתוב ברצף לקובץ? מה אם נרצה לכתוב את הברכה שלנו לקובץ שלוש פעמים ברציפות? הכל מאוד פשוט. מכיוון שהשפה לא יכולה לדעת איזו התנהגות אנחנו צריכים בכל מקרה, המעצב FileOutputStreamיכול לקחת פרמטר נוסף - boolean append. אם הערך שלו נכון, הנתונים ייכתבו לסוף הקובץ. אם הוא שקר (וברירת המחדל הוא שקר), כל נתונים ישנים יימחקו ויוחלף בנתונים חדשים. בוא נבדוק זאת על ידי הפעלת הקוד ששונה שלוש פעמים:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
} תוכן הקובץ:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers! עכשיו זה אחרת! אל תשכח את התכונה הזו בעת שימוש בשיעורי I/O. הייתה תקופה שבה ביליתי שעות במשימות, ביליתי שעות במוח, בניסיון להבין איך הנתונים שלי נעלמים מקבצים :) וכמובן, בדיוק כמו בשיעורי I/O אחרים, אל תשכחו להשתמש close()בשיטה לפנות משאבים.
המחלקה FileInputStream
למטרהFileInputStreamההפוכה - קריאת בתים מקובץ. בדיוק כמו FileOutputStreamיורשת OutputStream, מחלקה זו נובעת מהמחלקה InputStreamהמופשטת. נכתוב כמה שורות טקסט בקובץ " test.txt " שלנו:
"So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters"
הנה איך זה נראה לקרוא נתונים מקובץ באמצעות FileInputStream:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
int i;
while((i=fileInputStream.read())!= -1){
System.out.print((char)i);
}
}
} אנו קוראים בית אחד מהקובץ, ממירים את הבייטים הנקראים לתווים ומציגים אותם בקונסולה. והנה פלט הקונסולה:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
המחלקה BufferedInputStream
אני חושב, בהתחשב בידע משיעורי העבר, אתה יכול להגיד בקלות למה אנחנו צריכים את השיעורBufferedInputStreamואיזה יתרונות יש לו בהשוואה FileInputStream:) כבר נתקלנו בזרמים מאוחסנים, אז נסו לנחש (או לזכור) לפני שאתם ממשיכים לקרוא :) נחוצים זרמים ממוגנים בעיקר כדי לייעל את ה-I/O. גישה למקור נתונים, כמו קריאה מקובץ, היא פעולה יקרה מבחינת ביצועים ולגשת לקובץ כדי לקרוא כל בייט זה בזבוז. זו הסיבה BufferedInputStreamשקורא נתונים לא בייט אחד בכל פעם, אלא בבלוקים, ומאחסן אותם באופן זמני במאגר מיוחד. זה מאפשר לנו לייעל את התוכנית על ידי הפחתת מספר הפעמים שאנו ניגשים לקובץ. בוא נראה איך זה נראה:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
}
} כאן יצרנו אובייקט BufferedInputStream. הבנאי שלו לוקח מופע של InputStreamהמחלקה או כל אחד מהצאצאים שלה, כך גם FileInputStreamיעשה. כארגומנט נוסף, הוא לוקח את גודל המאגר בבתים. הודות לטיעון זה, הנתונים ייקראו כעת מהקובץ לא בייט אחד בכל פעם, אלא 200 בייט בכל פעם! תארו לעצמכם כמה צמצמנו את מספר הגישה לקבצים. כדי להשוות ביצועים, אתה יכול לקחת קובץ טקסט גדול (מספר מגה בייט של טקסט) ולהשוות את משך הזמן שלוקח באלפיות שניות לקרוא ולפלט לקונסולה באמצעות FileInputStreamו BufferedInputStream. הנה קוד שמדגים את שתי האפשרויות:
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");
int i;
while((i = fileInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
} כשקראתי קובץ של 1.5 מגה-בייט במחשב שלי, FileInputStreamהשלמתי את העבודה תוך ~3500 מילישניות, אבל BufferedInputStreamהצלחתי אותה תוך ~1700 מילישניות. כפי שאתה יכול לראות, הזרם המאוחסן ייעל את העבודה, חתך אותה לשניים! :) נמשיך ללמוד שיעורי I/O - נתראה בקרוב!
GO TO FULL VERSION