"سلام! در درس امروز، ما گفتگوی خود را در مورد جریان های ورودی و خروجی در جاوا ( Java I/O ) ادامه خواهیم داد. این اولین درس در مورد این موضوع نیست و مطمئنا آخرین درس نیز نخواهد بود
:) اتفاق میافتد، زبان جاوا راههای زیادی برای کار با 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
. اگر مقدار آن true باشد، داده ها در انتهای فایل نوشته می شوند. اگر نادرست باشد (و به طور پیش فرض نادرست است)، هر داده قدیمی پاک می شود و با داده جدید جایگزین می شود. بیایید این را با اجرای کد اصلاح شده خود سه بار بررسی کنیم:
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، این ویژگی را فراموش نکنید. close()
زمانی بود که ساعتها روی کارها وقت میگذاشتم، ساعتها ذهنم را درگیر میکردم، سعی میکردم بفهمم که چگونه دادههایم از فایلها ناپدید میشوند :) و البته، درست مانند سایر کلاسهای I/O، استفاده از این روش را فراموش نکنید. برای آزاد کردن منابع
کلاس 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
:) ما قبلاً با جریان های بافر مواجه شده ایم، بنابراین سعی کنید قبل از ادامه خواندن حدس بزنید (یا به خاطر بسپارید) :) جریان های بافر عمدتاً برای بهینه سازی ورودی/خروجی مورد نیاز هستند. دسترسی به یک منبع داده، مانند خواندن از روی یک فایل، از نظر کارایی یک عملیات پرهزینه است و دسترسی به یک فایل برای خواندن هر بایت بیهوده است. به همین دلیل است که 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