سلام! در سخنرانی امروز ما گفتگو را در مورد جریان های ورودی و خروجی در جاوا یا به اختصار 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 JavaRush - the best site for those who want to become a programmer!";
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 JavaRush - the best site for those who want to become a programmer!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
نتیجه در هر دو مورد یکسان خواهد بود. ما می توانیم پرونده خود را باز کنیم و آنجا را ببینیم:
Hello! Добро пожаловать на JavaRush — лучший сайт для тех, кто хочет стать программистом!
با این حال، در اینجا یک اخطار وجود دارد. سعی کنید کد مثال بالا را چندین بار پشت سر هم اجرا کنید و سپس به فایل نگاه کنید و به این سوال پاسخ دهید: چند خط در آن نوشته شده است؟ فقط یکی. اما شما کد را چندین بار اجرا کردید. با این حال، معلوم می شود که داده ها هر بار بازنویسی شده و جایگزین داده های قدیمی می شوند. اگر به این راضی نباشیم و نیاز به ضبط متوالی داشته باشیم چه؟ اگر بخواهیم احوالپرسی خود را سه بار پشت سر هم به یک فایل بنویسیم چه؟ اینجا همه چیز ساده است. از آنجایی که خود زبان نمی تواند بداند که در هر مورد به چه نوع رفتاری نیاز داریم، FileOutputStream
می توانید یک پارامتر اضافی را به سازنده ارسال کنید - boolean append
. اگر مقدار آن true باشد ، داده ها در انتهای فایل نوشته می شوند. اگر false باشد (و مقدار پیشفرض false باشد )، دادههای قدیمی پاک میشوند و دادههای جدید نوشته میشوند. بیایید کد اصلاح شده خود را سه بار آزمایش و اجرا کنیم:
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 JavaRush - the best site for those who want to become a programmer!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
نتیجه در فایل:
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
Hello! Добро пожаловать на JavaRush - лучший сайт для тех, кто хочет стать программистом!
یک چیز دیگر! هنگام استفاده از کلاس های 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 میلی ثانیه انجام داد. همانطور که می بینید، جریان بافر عملکرد برنامه را 2 برابر بهینه کرد! :) ما به مطالعه کلاس های I/O ادامه خواهیم داد - بعداً شما را می بینیم!
GO TO FULL VERSION