عملکرد فایل I/O در C++ تقریباً مشابه عملکرد ورودی/خروجی معمولی است (اما با چند تفاوت).

کلاس های ورودی/خروجی فایل

وجود دارد سه کلاس I/O فایل اصلی در C++:

خارج از جریان(فرزند کلاس است)؛

fstream(فرزند کلاس iostream است).

با این کلاس ها می توانید ورودی فایل یک طرفه، خروجی فایل یک طرفه و I/O فایل دو طرفه را انجام دهید. برای استفاده از آنها، فقط باید fstream را وصل کنید.

برخلاف جریان‌های cout، cin، cerr، و clog که بلافاصله قابل استفاده هستند، جریان‌های فایل باید به صراحت توسط برنامه‌نویس تنظیم شوند. یعنی برای باز کردن یک فایل برای خواندن و/یا نوشتن، باید یک شی از کلاس I/O فایل مناسب ایجاد کنید و نام فایل را به عنوان پارامتر مشخص کنید. سپس با استفاده از عملگرهای درج (<<) или извлечения (>>)، می توانید داده ها را در یک فایل بنویسید یا محتویات یک فایل را بخوانید. پس از آن، نهایی - شما باید فایل را ببندید: صریحاً تماس بگیرید متد close().یا فقط اجازه دهید متغیر I/O فایل از محدوده خارج شود (کلاس I/O فایل آن فایل را به طور خودکار برای ما می بندد).

خروجی فایل

کلاس ofstream برای نوشتن روی یک فایل استفاده می شود. مثلا:

#عبارتند از #عبارتند از #عبارتند از // برای استفاده از exit() int main() ( با استفاده از فضای نام std؛ // ofstream برای نوشتن داده در یک فایل استفاده می شود // ایجاد یک فایل SomeText.txt ofstream outf("SomeText.txt")؛ // اگر بتوانیم این فایل را برای نوشتن داده در if (!outf) باز نکنید ( // سپس یک پیام خطا چاپ کنید و exit() cerr را اجرا کنید<< "Uh oh, SomeText.txt could not be opened for writing!" << endl; exit(1); } // Записываем в файл следующие две строчки outf << "See line #1!" << endl; outf << "See line #2!" << endl; return 0; // Когда outf выйдет из области видимости, то деструктор класса ofstream автоматически закроет наш файл }

#عبارتند از

#عبارتند از

#عبارتند از // برای استفاده از exit()

int main()

با استفاده از namespace std ;

// ofstream برای نوشتن داده ها در فایل استفاده می شود

// فایل SomeText.txt ایجاد کنید

ofstream outf("SomeText.txt") ;

// اگر نتوانیم این فایل را برای نوشتن داده در آن باز کنیم

اگر (!outf)

// سپس یک پیام خطا چاپ کنید و exit() را اجرا کنید

cerr<< << endl ;

خروج (1) ;

// دو خط زیر را در فایل بنویسید

خارج کردن<< "See line #1!" << endl ;

خارج کردن<< "See line #2!" << endl ;

بازگشت 0 ;

// وقتی outf از محدوده خارج شود، تخریب کننده کلاس ofstream به طور خودکار فایل ما را می بندد

اگر به دایرکتوری پروژه خود نگاه کنید ( RMB روی برگه با نام فایل cpp. شما در ویژوال استودیو > "باز کردن پوشه حاوی"، فایلی به نام SomeText.txt را مشاهده می کنید که حاوی خطوط زیر است:

خط شماره 1 را ببینید!
خط شماره 2 را ببینید!

لطفا توجه داشته باشید که ما نیز می توانیم استفاده کنیم روش put().برای نوشتن یک کاراکتر در یک فایل

ورودی فایل

#عبارتند از #عبارتند از #عبارتند از #عبارتند از // برای استفاده از exit() int main() ( با استفاده از فضای نام std؛ // ifstream برای خواندن محتویات فایل استفاده می شود // سعی کنید محتویات فایل SomeText.txt را بخوانید ifstream inf("SomeText.txt") ; // اگر نتوانیم این فایل را برای خواندن محتویات آن باز کنیم اگر (!inf) ( cerr<< "Uh oh, SomeText.txt could not be opened for reading!" << endl; exit(1); } // Пока есть данные, которые мы можем прочитать while (inf) { // То перемещаем эти данные в строку, которую затем выводим на экран string strInput; inf >> strInput; کوت<< strInput << endl; } return 0; }

#عبارتند از

#عبارتند از

#عبارتند از

#عبارتند از // برای استفاده از exit()

int main()

با استفاده از namespace std ;

// ifstream برای خواندن محتویات فایل استفاده می شود

// اگر نتوانیم این فایل را برای خواندن محتوای آن باز کنیم

اگر (!inf)

// سپس پیغام خطای زیر را چاپ کرده و exit() را اجرا کنید.

cerr<< << endl ;

خروج (1) ;

// تا زمانی که داده ای وجود دارد می توانیم بخوانیم

در حالی که (inf)

// سپس این داده ها را به یک رشته منتقل می کنیم که سپس آن را روی صفحه نمایش می دهیم

رشته strInput ;

inf >> strInput ;

کوت<< strInput << endl ;

بازگشت 0 ;

// هنگامی که inf از محدوده خارج می شود، تخریب کننده کلاس ifstream به طور خودکار فایل ما را می بندد

دیدن
خط
#1!
دیدن
خط
#2!

هوم، این چیزی نیست که ما می خواستیم. همانطور که قبلاً از درس های قبلی می دانیم، عملگر استخراج با "داده های قالب بندی شده" کار می کند. تمام فضاها، تب ها و خطوط جدید را نادیده می گیرد. برای خواندن تمام مطالب همانطور که هست، بدون تقسیم آن به بخش (مانند مثال بالا)، باید از آن استفاده کنیم متد getline().:

#عبارتند از #عبارتند از #عبارتند از #عبارتند از // برای استفاده از exit() int main() ( با استفاده از فضای نام std؛ // ifstream برای خواندن محتویات فایل ها استفاده می شود // سعی می کنیم محتویات فایل SomeText.txt را بخوانیم ifstream inf("SomeText.txt") ; // اگر نمی توانیم فایلی را برای خواندن محتویات آن باز کنیم اگر (!inf) ( // سپس پیغام خطای زیر را چاپ کرده و exit() cerr<< "Uh oh, SomeText.txt could not be opened for reading!" << endl; exit(1); } // Пока есть, что читать while (inf) { // То перемещаем то, что можем прочитать, в строку, а затем выводим эту строку на экран string strInput; getline(inf, strInput); cout << strInput << endl; } return 0; // Когда inf выйдет из области видимости, то деструктор класса ifstream автоматически закроет наш файл }

#عبارتند از

#عبارتند از

#عبارتند از

#عبارتند از // برای استفاده از exit()

int main()

با استفاده از namespace std ;

// ifstream برای خواندن محتویات فایل ها استفاده می شود

ifstream inf("SomeText.txt") ;

// اگر نتوانیم فایل را برای خواندن محتوای آن باز کنیم

اگر (!inf)

// سپس پیغام خطای زیر را چاپ کرده و exit() را اجرا کنید.

cerr<< "اوه اوه، SomeText.txt برای خواندن باز نشد!"<< endl ;

خروج (1) ;

در حالی که (inf)

رشته strInput ;

getline (inf , strInput ) ;

کوت<< strInput << endl ;

بازگشت 0 ;

// هنگامی که inf از محدوده خارج می شود، تخریب کننده کلاس ifstream به طور خودکار فایل ما را می بندد

نتیجه اجرای برنامه بالا این است:

خروجی بافر

خروجی در C++ را می توان بافر کرد. این بدان معناست که هر چیزی که به جریان فایل خروجی می‌شود نمی‌تواند بلافاصله روی دیسک (در یک فایل خاص) نوشته شود. این در درجه اول به دلایل عملکرد انجام می شود. هنگامی که داده های بافر روی دیسک نوشته می شود، این فراخوانی می شود پاک کردن بافر. یکی از راه های پاک کردن بافر، بستن فایل است. در این حالت کل محتویات بافر به دیسک منتقل می شود و سپس فایل بسته می شود.

بافر خروجی معمولاً مشکلی ایجاد نمی کند، اما در شرایط خاص می تواند برای تازه کارهای بی احتیاط مشکل ایجاد کند. به عنوان مثال، زمانی که داده ها در بافر ذخیره می شوند و برنامه اجرای آن را پیش از موعد متوقف می کند (چه در نتیجه خرابی یا با فراخوانی ). در چنین مواردی، تخریب کننده های کلاس I/O فایل اجرا نمی شوند، فایل ها هرگز بسته نمی شوند، بافرها پاک نمی شوند و داده های ما برای همیشه از بین می روند. به همین دلیل ایده خوبی است که قبل از فراخوانی exit() به صراحت تمام فایل های باز را ببندید.

همچنین می توانید بافر را به صورت دستی پاک کنید روش ostream::flush().یا با ارسال std:: flushبه جریان خروجی هر یک از این روش ها می تواند برای اطمینان از اینکه محتویات بافر در صورت خرابی برنامه فوراً روی دیسک نوشته می شود مفید باشد.

یک تفاوت ظریف جالب: چون std::endl; همچنین جریان خروجی را پاک می کند، سپس استفاده بیش از حد از آن (که منجر به فلاش های غیرضروری بافر می شود) می تواند بر عملکرد برنامه تأثیر بگذارد (زیرا فلاشینگ بافر در برخی موارد می تواند گران باشد). به همین دلیل، برنامه نویسان آگاه به عملکرد اغلب به جای std::endl از \n برای درج یک خط جدید در جریان خروجی استفاده می کنند تا از شستشوی غیرضروری بافر جلوگیری کنند.

حالت های باز کردن فایل

اگر بخواهیم داده ها را در یک فایل موجود بنویسیم چه اتفاقی می افتد؟ اجرای مجدد برنامه بالا (همان اولی) نشان می دهد که با اجرای مجدد برنامه، فایل اصلی کاملاً رونویسی شده است. اما اگر نیاز به اضافه کردن داده به انتهای فایل داشته باشیم، چه؟ به نظر می رسد که جریان فایل یک پارامتر دوم اختیاری را می گیرد که به شما امکان می دهد به برنامه نویس بگویید چگونه فایل را باز کند. به عنوان این پارامتر، می توانید عبور دهید پرچم های زیر(که در کلاس ios هستند):

برنامه- فایل را در حالت الحاق باز می کند.

خورد- قبل از خواندن/نوشتن به انتهای فایل می رود.

دودویی- فایل را در حالت باینری (به جای حالت متنی) باز می کند.

که در- فایل را در حالت خواندن باز می کند (پیش فرض برای ifstream).

بیرون- فایل را در حالت نوشتن باز می کند (پیش فرض برای جریان).

تنه- فایل را در صورت وجود حذف می کند.

می توانید با استفاده از .

ifstream بصورت پیش فرض در حالت ios::in کار می کند.

ofstream به طور پیش فرض در حالت ios::out کار می کند.

fstream به طور پیش فرض در حالت ios:: در OR ios::out اجرا می شود، به این معنی که می توانید محتویات یک فایل را بخوانید یا داده ها را در یک فایل بنویسید.

حالا بیایید برنامه ای بنویسیم که دو خط به فایل SomeText.txt ایجاد شده قبلی اضافه کند:

#عبارتند از #عبارتند از // برای استفاده از exit() #include int main() ( با استفاده از namespace std؛ // با ارسال پرچم ios:app به fstream می‌گوییم که داده‌هایمان را به داده‌های موجود فایل اضافه می‌کنیم، // فایل را رونویسی نمی‌کنیم. باید پرچم ios::out را ارسال کنید، // از آنجایی که ofstream به صورت پیش‌فرض روی ios::out ofstream است outf("SomeText.txt", ios::app)؛ // اگر نتوانیم فایلی را برای نوشتن داده باز کنیم، اگر (!outf) ( // سپس پیغام خطای زیر را خروجی و exit()cerr را صادر کنید<< "Uh oh, SomeText.txt could not be opened for writing!" << endl; exit(1); } outf << "See line #3!" << endl; outf << "See line #4!" << endl; return 0; // Когда outf выйдет из области видимости, то деструктор класса ofstream автоматически закроет наш файл }

#عبارتند از

#عبارتند از // برای استفاده از exit()

#عبارتند از

int main()

با استفاده از namespace std ;

// با ارسال پرچم ios:app به fstream می‌گوییم که داده‌های خود را به داده‌های موجود فایل اضافه می‌کنیم،

// قرار نیست فایل را بازنویسی کنیم. نیازی نیست که پرچم ios::out را پاس کنیم،

// زیرا ofstream حالت پیش فرض ios::out را دارد

ofstream outf("SomeText.txt" , ios::app ) ;

// اگر نتوانیم فایل را برای نوشتن داده باز کنیم

اگر (!outf)

// سپس پیغام خطای زیر را چاپ کرده و exit() را اجرا کنید.

cerr<< "اوه اوه، SomeText.txt برای نوشتن باز نشد!"<< endl ;

خروج (1) ;

مکانیسم I/O توسعه یافته توسط، با سبک عمومی پذیرفته شده برنامه نویسی شی گرا امروز مطابقت ندارد، علاوه بر این، به طور فعال از عملیات اشاره گر استفاده می کند که در محیط های اجرای کد ایمن مدرن به طور بالقوه ناامن تلقی می شوند. یک جایگزین برای توسعه اپلیکیشن مکانیسم استاندارد کلاس I/O است که توسط استاندارد زبان C++ ارائه شده است.

باز کردن فایل ها

رایج ترین کلاس های مورد استفاده ifstream برای خواندن، ofstream برای نوشتن و fstream برای تغییر فایل ها هستند.

تمام کلاس‌های ورودی/خروجی رشته‌ای به‌طور غیرمستقیم از اجداد مشترک ios مشتق شده‌اند و به طور کامل عملکرد آن را به ارث می‌برند. به عنوان مثال، عضو داده شمارش شده open_mode حالت باز فایل را مشخص می کند که به صورت زیر تعریف می شود:

Enum open_mode (برنامه، باینری، داخل، خارج، ترانک، خورده)؛

در زیر مقادیر احتمالی پرچم ها و هدف آنها آورده شده است.

به عنوان مثال، برای باز کردن فایلی به نام test.txt برای خواندن داده های باینری، باید بنویسید:

فایل ifstream; file.open("test.txt", ios::in | ios::binary);

عملگر منطقی OR (|) به شما امکان می دهد یک حالت با هر ترکیبی از پرچم ها بسازید. برای اینکه هنگام باز کردن یک فایل با نوشتن، به طور تصادفی فایل موجود با همین نام را بازنویسی نکنید، باید از فرم زیر استفاده کنید:

فایل خارج از جریان؛ file.open("test.txt", ios::out | ios::app);

فرض بر این است که فایل هدر مناسب به پروژه متصل است:

#عبارتند از

برای بررسی اینکه آیا فایل با موفقیت باز شده است، می توانید از ساختار استفاده کنید

اگر (! فایل) ( // رسیدگی به خطای باز کردن فایل )

اپراتورهای گنجاندن و استخراج

در کلاس های مدیریت فایل لغو شد شامل اپراتور (<<) записывает данные в файловый поток. Как только вы открыли файл для записи, можно записывать в него текстовую строку целиком:

فایل<< "Это строка текста";

شما همچنین می توانید یک رشته متن را به صورت قطعات بنویسید:

فایل<< "Это " << "строка " << "текста";

دستور endl ورودی خط را با بازگشت باری به پایان می رساند:

فایل<< "Это строка текста" << endl;

با استفاده از عملگر include، نوشتن مقادیر متغیرها یا عناصر آرایه در یک فایل آسان است:

فایل Offstream ("Temp.txt"); char buff = "آرایه متن حاوی متغیرهایی است"; int vx = 100; float pi = 3.14159; فایل<< buff << endl << vx << endl << pi << endl;

در نتیجه اجرای کد، سه خط از فایل متنی Temp.txt ایجاد می شود:

آرایه متن شامل متغیرهای 100 3.14159 است

توجه داشته باشید که مقادیر عددی به صورت رشته های متنی در فایل نوشته می شوند نه مقادیر باینری.

عملگر استخراج(>>) برعکس عمل می کند. به نظر می رسد برای استخراج کاراکترها از فایل Temp.txt که قبلا نوشته شده است، باید کدی مانند زیر بنویسید:

فایل ifstream ("Temp.txt"); char buff; intvx; floatpi; فایل >> buff >> vx >> pi;

با این حال، عملگر استخراج در اولین جداکننده (فضا، برگه یا خط جدید) که با آن مواجه می شود متوقف می شود. بنابراین، هنگام تجزیه جمله "آرایه متنی حاوی متغیرها"، فقط کلمه "Text" به آرایه buff نوشته می شود، فاصله نادیده گرفته می شود و کلمه "array" به مقدار متغیر عدد صحیح vx و کد تبدیل می شود. اجرا با تخطی اجتناب ناپذیر از ساختار داده ها "هیجان زده" خواهد شد. در مرحله بعد، هنگام بحث در مورد کلاس ifstream، نحوه سازماندهی صحیح خواندن فایل از مثال قبلی را نشان خواهیم داد.

کلاس ifstream: خواندن فایل ها

همانطور که از نام آن پیداست، کلاس ifstream برای ورودی یک جریان فایل طراحی شده است. متدهای اصلی کلاس در زیر فهرست شده است. اکثر آنها از کلاس istream به ارث رسیده و با عملکرد والد بارگذاری شده اند. به عنوان مثال، تابع get، بسته به پارامتر فراخوانی، قادر است نه تنها یک کاراکتر، بلکه یک بلوک کاراکتر را نیز بخواند.

اکنون مشخص است که چگونه باید مثال قبلی را تغییر دهید تا با استفاده از عملگر استخراج داده نتیجه مورد انتظار را به دست آورید:

فایل ifstream ("Temp.txt"); char buff; intvx; floatpi; file.getline(buff, sizeof(buff)); فایل >> vx >> pi:

متد getline خط اول فایل را تا آخر می خواند و عملگر >> مقادیری را به متغیرها اختصاص می دهد.

مثال زیر اضافه کردن داده به یک فایل متنی و سپس خواندن کل فایل را نشان می دهد. حلقه while (1) به جای while(!file2.eof()) به دلایلی که در .

#عبارتند از #عبارتند از با استفاده از namespace std. int main() ( فایل جریان؛ file.open ("test.txt"، ios::out|ios::app)؛ if (!file) (cout<< "File error - can"t open to write data!"; cin.sync(); cin.get(); return 1; } for (int i=0; i<10; i++) file << i << endl; file.close(); ifstream file2; file2.open("test.txt", ios::in); if (!file2) { cout << "File error - can"t open to read data!"; cin.sync(); cin.get(); return 2; } int a,k=0; while (1) { file2 >>a; if (file2.eof()) break; کوت<< a << " "; k++; } cout << endl << "K=" << k << endl; file2.close(); cin.sync(); cin.get(); return 0; }

مثال زیر از طریق خواندن خطوط از فایل test.txt و نمایش آنها بر روی کنسول حلقه می زند.

#عبارتند از #عبارتند از با استفاده از namespace std. int main() (فایل ifstream؛ // ایجاد یک فایل شی جریانی file.open("test.txt")؛ // فایل را برای خواندن باز کنید اگر (!file) 1 را بازگرداند؛ // بازگشت خطای باز کردن char str؛ / / بافر خط استاتیک // خواندن و نمایش خطوط در یک حلقه تا eof در حالی که (!file.getline(str, sizeof(str)).eof()) cout<< str << endl; // вывод прочитанной строки на экран cin.sync(); cin.get(); return 0; }

این کد تحت سیستم عامل ویندوز همچنین به وجود یک کاراکتر خط جدید در آخرین خط فایل بستگی دارد، انجام این کار قابل اعتمادتر است:

while (1) ( if (file.eof()) break؛ file.getline(str, sizeof(str))؛ cout<< str << endl; }

فراخوانی صریح به روش های باز و بسته اختیاری است. در واقع، فراخوانی سازنده با آرگومان به شما این امکان را می دهد که فایل را بلافاصله در لحظه ایجاد شی جریان فایل باز کنید:

فایل ifstream("test.txt");

به جای روش بستن، می توانید از اپراتور حذف استفاده کنید که به طور خودکار Destructor شی فایل را فراخوانی می کند و فایل را می بندد. کد حلقه while بررسی صحیح انتهای فایل را فراهم می کند.

کلاس ofstream: نوشتن فایل

کلاس ofstream برای خروجی داده از جریان فایل طراحی شده است. متدهای اصلی این کلاس در زیر ذکر شده است.

عملگر شامل که قبلا توضیح داده شد برای سازماندهی نوشتن در یک فایل متنی مناسب است:

فایل Offstream ("temp.txt"); اگر (!فایل) بازگشت; برای (int i=1; i<=3; i++) file << "Строка " << i << endl; file.close();

باینری ها

در اصل، داده های باینری مانند داده های متنی ارائه می شوند. تفاوت این است که اگر داده های باینری در یک ساختار منطقی خاص نوشته شده باشند، باید از فایل به متغیری از همان نوع ساختار خوانده شوند.

اولین پارامتر متدهای نوشتن و خواندن (آدرس بلوک نوشتن/خواندن) باید از نوع نشانگر کاراکتر char * باشد، بنابراین لازم است به صراحت نوع آدرس ساختار void * را تبدیل کنید. پارامتر دوم مشخص می کند که بلوک های باینری فایل بدون توجه به طول رکورد واقعی، اندازه بایت ثابتی دارند. پیوست زیر مثالی از نحوه ایجاد و نمایش داده ها در یک نوت بوک ساده ارائه می دهد. سپس رکوردهای فایل به صورت متوالی خوانده می شوند و در کنسول نمایش داده می شوند.

#عبارتند از #عبارتند از #عبارتند از با استفاده از namespace std. struct Notes ( // ساختار داده char نوت بوک نام; // نام کامل char تلفن; // phone int Age; // age ); int main() (setlocale(LC_ALL، "روسی")؛ یادداشت ها Note1= ("Grozny Ioann Vasilyevich"، "نصب نشده است"، 60)؛ Notes Note2= ("Godunov Boris Fedorovich"، "095-111-2233"، 30)؛ یادداشت ها Note3= ("پیتر رومانوف"، "812-333-2211"، 20); ofstream ofile ("Notebook.dat"، ios::binary); ofile.write((char*)&Note1, sizeof ( یادداشت ها))؛ // بلوک اول ofile.write((char*)&Note2, sizeof(Notes)); // بلوک دوم ofile.write((char*)&Note3, sizeof(Notes))؛ / / بلوک سوم ofile. close(); // بستن فایل نوشته شده ifstream ifstream("Notebook.dat", ios::binary); یادداشت ها توجه؛ // متغیر ساختاری char str؛ // بافر رشته ایستا // خواندن و نمایش خطوط در یک حلقه تا زمانی که eof while (!ifile.read((char*)&Note, sizeof(Notes)).eof()) ( sprintf(str, "%s\tBody: %s\tAge: %d" , Note.Name, Note. تلفن، Note.Age)؛ cout<< str << endl; } ifile.close(); // закрыть прочитанный файл cin.sync(); cin.get(); return 0; }

در نتیجه اجرای این کد، یک فایل باینری Notebook.dat از سه بلوک 80 بایتی هر کدام (با فرض تک بایت بودن کاراکترها) تشکیل می شود. طبیعتاً می‌توانید از روش‌های دیگر استریم استفاده کنید و هر عملیاتی را روی فیلدهای یک ساختار داده خاص انجام دهید.

کلاس fstream: دسترسی تصادفی به فایل

فرض کنید دفترچه ما 100 مدخل جمع کرده است و می خواهیم 50 را بشماریم. البته، می توانید یک حلقه سازماندهی کنید و تمام رکوردها را از اول تا مورد داده شده بخوانید. بدیهی است که راه حل هدفمندتر این است که نشانگر موقعیت فایل pos را مستقیماً روی ورودی 50 تنظیم کنید و آن را بخوانید:

ifstream ifile("Notebook.dat", ios::binary); int pos = 49 * sizeof(Notes); ifile seek(pos); // جستجو برای ورودی 50 یادداشت ها توجه; //Notes - ساختار "رکورد" که در بالا توضیح داده شد ifile.read((char*)&Note, sizeof(Notes));

چنین عملیات جستجو در صورتی موثر است که فایل شامل رکوردهایی با اندازه مشخص و ثابت باشد. برای جایگزینی محتوای یک ورودی دلخواه، باید جریان خروجی را در حالت اصلاح باز کنید:

Offstream ofile("Notebook.dat", ios::binary | ios::ate); int pos = 49 * sizeof(Notes); ofile seekp(pos); // نت 50 را جستجو کنید Note50 = ("Yeltsin Boris Nikolaevich", "095-222-3322", 64); ofile.write((char*)&Note, sizeof(Notes)); // جایگزینی

اگر پرچم ios::ate (یا ios::app) را مشخص نکنید، وقتی فایل باینری Notebook.dat را باز می کنید، محتویات قبلی آن پاک می شود!

در نهایت، با استفاده از روش هایی که کلاس جریان fstream از پیشینیان خود به ارث برده است، می توان یک فایل را همزمان برای خواندن/نوشتن باز کرد. از آنجایی که کلاس fstream از istream و ostream (به ترتیب والدین ifstream و ofstream) مشتق شده است، همه روش‌های ذکر شده قبلاً در دسترس برنامه قرار می‌گیرند.

مثال زیر ورودی های اول و سوم را در فایل Notebook.dat تعویض می کند.

#عبارتند از #عبارتند از #عبارتند از با استفاده از namespace std. یادداشت‌های ساختاری (نام کاراکتر؛ تلفن کاراکتر؛ سن بین‌المللی؛ ); int main() ( setlocale(LC_ALL، "روسی")؛ یادداشت ها Note1، Note3؛ // باز کردن فایل برای خواندن/نوشتن همزمان فایل fstream("Notebook.dat"، ios::binary | ios::in | ios:: out); file.seekg(2 * sizeof(Notes)); // Note3 file.read((char*)&Note3, sizeof(Notes)) را پیدا و بخوانید؛ file.seekg(0)؛ // Note1 را پیدا و بخوانید file.read((char*)&Note1, sizeof(Notes)); file.seekg(0); // Note1<== Note3 file.write((char*)&Note3, sizeof(Notes)); file.seekg(2 * sizeof(Notes)); // Note3 <== Note1 file.write((char*)&Note1, sizeof(Notes)); char str; // Считывать и отображать записи в цикле, пока не eof file.seekg(0); // вернуться к началу файла while (!file.read((char*)&Note1, sizeof(Notes)).eof()) { sprintf(str, "%s\tТел: %s\tВозраст: %d", Note1.Name, Note1.Phone, Note1.Age); cout << str << endl; } file.close(); cin.sync(); cin.get(); return 0; }

پرچم های ios::in و ios::out باید در سازنده شی فایل مشخص شوند تا عملیات خواندن و نوشتن همزمان امکان پذیر باشد. در نتیجه اجرای این کد، رکوردهای اول و سوم فایل باینری Notebook.dat مبادله می شوند.

مثال های اضافی در مورد موضوع وجود دارد.

اکثر برنامه های کامپیوتری با فایل ها کار می کنند و بنابراین نیاز به ایجاد، حذف، نوشتن، خواندن، باز کردن فایل ها وجود دارد. فایل چیست؟ یک فایل مجموعه ای با نام از بایت ها است که می تواند در برخی از دستگاه های ذخیره سازی ذخیره شود. خوب، اکنون مشخص است که یک فایل دنباله ای از بایت است که نام منحصر به فرد خود را دارد، مانند یک فایل txt. فایل هایی با نام یکسان نمی توانند در یک دایرکتوری باشند. نام فایل نه تنها به عنوان نام آن، بلکه به عنوان یک پسوند نیز درک می شود، به عنوان مثال: file.txt و file.dat فایل های مختلف، اگرچه نام یکسانی دارند. چیزی به نام نام کامل فایل ها وجود دارد - این آدرس کامل دایرکتوری فایل با نام فایل است، به عنوان مثال: D:\docs\file.txt . درک این مفاهیم اساسی مهم است، در غیر این صورت کار با فایل ها دشوار خواهد بود.

برای کار با فایل ها، باید یک فایل هدر اضافه کنید . AT چندین کلاس تعریف شده و فایل های هدر گنجانده شده است ورودی فایل و خروجی فایل

ورودی/خروجی فایل مشابه ورودی/خروجی استاندارد است، تنها تفاوت این است که ورودی/خروجی روی صفحه نمایش انجام نمی شود، بلکه روی یک فایل انجام می شود. اگر ورودی/خروجی به دستگاه های استاندارد با استفاده از اشیاء cin و cout انجام می شود، برای سازماندهی I/O فایل کافی است اشیاء خود را ایجاد کنید که می توانند مشابه عملگرهای cin و cout استفاده شوند.

برای مثال، باید یک فایل متنی ایجاد کنید و خط Working with files در C++ را در آن بنویسید. برای این کار باید مراحل زیر را انجام دهید:

  1. یک شی از کلاس ofstream ایجاد کنید ;
  2. ارتباط یک شی کلاس با فایلی که باید در آن نوشته شود.
  3. نوشتن یک خط در یک فایل؛
  4. فایل را ببندید

چرا باید یک شی از کلاس ofstream ایجاد کرد و نه کلاس ifstream؟ زیرا باید در یک فایل بنویسید و اگر نیاز به خواندن داده ها از یک فایل دارید، یک شی از کلاس ifstream ایجاد می شود.

// ایجاد یک شی برای نوشتن در فایل ofstream /*object name*/; // شیء کلاس ofstream

بیایید شی را نام ببریم - fout، در اینجا چه اتفاقی می افتد:

جریان فاوت;

چرا به یک شی نیاز داریم؟ شی مورد نیاز است تا بتواند روی فایل بنویسد. شی قبلا ایجاد شده است، اما با فایلی که رشته باید روی آن نوشته شود، مرتبط نیست.

fout.open("cppstudio.txt"); // شیء را با فایل مرتبط کنید

از طریق عمل نقطه به متد کلاس open() دسترسی پیدا می کنیم که در پرانتز آن نام فایل را مشخص می کنیم. فایل مشخص شده در دایرکتوری فعلی با برنامه ایجاد می شود. اگر فایلی با همین نام وجود داشته باشد، فایل موجود با فایل جدید جایگزین می شود. بنابراین، فایل باز است، باقی مانده است که خط مورد نظر را در آن بنویسید. به این صورت انجام می شود:

فوت<< "Работа с файлами в С++"; // запись строки в файл

با استفاده از cast برای استریم کردن عملیات همراه با شی fout، رشته مدیریت فایل در C++ در یک فایل نوشته می‌شود. از آنجایی که دیگر نیازی به تغییر محتوای فایل نیست، باید بسته شود، یعنی شی باید از فایل جدا شود.

fout.close(); // فایل را ببندید

در نتیجه فایلی با خط Working with files در C++ ایجاد شد.

مراحل 1 و 2 را می توان ترکیب کرد، یعنی در یک خط، یک شی ایجاد کنید و آن را با یک فایل مرتبط کنید. به این صورت انجام می شود:

Ofstream fout("cppstudio.txt"); // یک شی از کلاس ofstream ایجاد کنید و آن را با فایل cppstudio.txt مرتبط کنید

بیایید همه کدها را با هم ترکیب کنیم و برنامه زیر را دریافت کنیم.

// file.cpp: نقطه ورودی برنامه کنسول را تعریف می کند. #include "stdafx.h" #include با استفاده از namespace std. int main(int argc, char* argv) ( ofstream fout("cppstudio.txt"); // یک شی از کلاس ofstream برای نوشتن ایجاد کنید و آن را با فایل cppstudio.txt fout مرتبط کنید<< "Работа с файлами в С++"; // запись строки в файл fout.close(); // закрываем файл system("pause"); return 0; }

باقی مانده است که عملکرد صحیح برنامه را بررسی کنیم و برای این کار فایل را باز می کنیم cppstudio.txt و به محتویات آن نگاه کنید، باید اینطور باشد -کار با فایل ها در C++

  1. یک شی از کلاس ifstream ایجاد کنید و آن را با فایلی که باید از آن خوانده شود مرتبط کنید.
  2. خواندن فایل؛
  3. فایل را ببندید
// file_read.cpp: نقطه ورودی برنامه کنسول را تعریف می کند. #include "stdafx.h" #include #عبارتند از با استفاده از namespace std. int main(int argc, char* argv) ( setlocale(LC_ALL, "rus"); // نمایش صحیح حروف سیریلیک char buff؛ // بافر ذخیره سازی میانی متن خوانده شده از فایل ifstream fin("cppstudio.txt ")؛ // فایل را برای خواندن fin >> باز کرد<< buff << endl; // напечатали это слово fin.getline(buff, 50); // считали строку из файла fin.close(); // закрываем файл cout << buff << endl; // напечатали эту строку system("pause"); return 0; }

این برنامه دو روش برای خواندن از یک فایل نشان می دهد، اولی استفاده از عملیات انتقال به جریان، دومی استفاده از تابع getline() . در حالت اول فقط کلمه اول خوانده می شود و در حالت دوم یک رشته 50 کاراکتری خوانده می شود. اما از آنجایی که کمتر از 50 کاراکتر در فایل باقی مانده است، کاراکترها تا آخرین کاراکتر خوانده می شوند. توجه داشته باشید که خواندن برای بار دوم (خط 17) بعد از اولین کلمه ادامه یافت و نه از ابتدا، زیرا کلمه اول در خوانده شدخط 14. نتیجه برنامه در شکل 1 نشان داده شده است.

کار با فایل ها در C++ برای ادامه هر کلیدی را فشار دهید. . .

شکل 1 - کار با فایل ها در C++

برنامه به درستی کار می کرد، اما همیشه اینطور نیست، حتی اگر همه چیز با کد مرتب باشد. به عنوان مثال، نام فایلی که وجود ندارد به برنامه ارسال شده است یا در نام آن خطایی رخ داده است. بعدش چی شد؟ در این صورت اصلاً هیچ اتفاقی نخواهد افتاد. فایل پیدا نمی شود، یعنی امکان خواندن آن وجود ندارد. بنابراین، کامپایلر خطوطی که فایل در آن دستکاری می شود را نادیده می گیرد. در نتیجه، برنامه به درستی خارج می شود، اما چیزی روی صفحه نمایش داده نمی شود. به نظر می رسد که این یک واکنش کاملا طبیعی به چنین وضعیتی است. اما یک کاربر ساده متوجه نخواهد شد که موضوع چیست و چرا خطی از فایل روی صفحه ظاهر نمی شود. بنابراین، برای اینکه همه چیز بسیار واضح باشد، C++ چنین تابعی را ارائه می‌کند - is_open() که مقادیر صحیح را برمی‌گرداند: 1 - اگر فایل با موفقیت باز شد، 0 - اگر فایل باز نشد. با باز شدن فایل برنامه را نهایی کنیم به این صورت که اگر فایل باز نشد پیغام مربوطه نمایش داده شود.

// file_read.cpp: نقطه ورودی برنامه کنسول را تعریف می کند. #include "stdafx.h" #include #عبارتند از با استفاده از namespace std. int main(int argc, char* argv) ( setlocale(LC_ALL, "rus"); // نمایش صحیح char buff سیریلیک؛ // بافر ذخیره سازی میانی متن خوانده شده از فایل ifstream fin ("cppstudio.doc")؛ / / ( نام فایل نادرست وارد شده است) اگر (!fin.is_open()) // اگر فایل باز نیست cout<< "Файл не может быть открыт!\n"; // сообщить об этом else { fin >> گاومیش؛ // اولین کلمه را از فایل cout بخوانید<< buff << endl; // напечатали это слово fin.getline(buff, 50); // считали строку из файла fin.close(); // закрываем файл cout << buff << endl; // напечатали эту строку } system("pause"); return 0; }

نتیجه برنامه در شکل 2 نشان داده شده است.

فایل باز نمیشه! کلیدی را برای ادامه فشار دهید. . .

شکل 2 - کار با فایل ها در C++

همانطور که در شکل 2 مشاهده می کنید، برنامه گزارش داد که فایل باز نمی شود. بنابراین، اگر برنامه با فایل ها کار می کند، توصیه می شود از این تابع is_open() استفاده کنید، حتی اگر از وجود فایل مطمئن هستید.

حالت های باز کردن فایل

حالت های باز کردن فایل، نحوه استفاده از فایل ها را تعیین می کند. برای تنظیم حالت، کلاس ios_base ثابت هایی را ارائه می دهد که حالت باز کردن فایل را تعیین می کند (جدول 1 را ببینید).

حالت های باز کردن فایل را می توان به طور مستقیم هنگام ایجاد یک شی یا هنگام فراخوانی تابع open () تنظیم کرد .

Ofstream fout("cppstudio.txt", ios_base::app); // فایل را برای افزودن اطلاعات به انتهای فایل باز کنید open("cppstudio.txt", ios_base::app); // فایل را برای افزودن اطلاعات به انتهای فایل باز کنید

حالت های باز فایل را می توان با استفاده از یک عملیات بولی بیتی ترکیب کرد یا| به عنوان مثال: ios_base::out | ios_base::trunc - پس از پاک کردن، یک فایل را برای نوشتن باز کنید.

اشیاء کلاس ofstream، وقتی با فایل‌ها مرتبط می‌شوند، به طور پیش‌فرض دارای حالت‌های باز فایل هستند ios_base::out | ios_base::trunc . یعنی فایل در صورت نبودن ایجاد می شود. اگر فایل وجود داشته باشد، محتویات آن حذف می شود و خود فایل برای ضبط آماده می شود. اشیاء کلاس ifstream، هنگامی که با یک فایل مرتبط می شوند، به طور پیش فرض حالت باز کردن فایل را دارند ios_base::in - فایل فقط برای خواندن باز است. حالت باز کردن فایل را پرچم نیز می نامند، برای خوانایی در آینده از این عبارت استفاده خواهیم کرد. جدول 1 همه پرچم‌ها را فهرست نمی‌کند، اما اینها باید برای شروع کافی باشند.

لطفاً توجه داشته باشید که پرچم‌های ate و app از نظر توضیحات بسیار شبیه به هم هستند، هر دو نشانگر را به انتهای فایل منتقل می‌کنند، اما پرچم برنامه فقط تا انتهای فایل اجازه نوشتن را می‌دهد، و پرچم ate پرچم را به سادگی مرتب می‌کند. پایان فایل است و فضای ضبط را محدود نمی کند.

بیایید برنامه ای ایجاد کنیم که با استفاده از عملیات sizeof() مشخصات انواع داده های اصلی را در C++ محاسبه کرده و در یک فایل بنویسد. مشخصات:

  1. تعداد بایت های اختصاص داده شده برای نوع داده
  2. حداکثر مقداری که یک نوع داده خاص می تواند ذخیره کند.

نوشتن در یک فایل باید در قالب زیر باشد:

/* نوع داده بایت حداکثر مقدار bool = 1 255.00 char = 1 255.00 کوتاه int = 2 32767.00 int int امضا نشده = 2 65535.00 int = 4 2147483647.00 int بدون امضا = 4 4294967295.00 long int = 4 2147483647.00 int int = 4 4296 شناور طولانی = 8 9223372036854775800.00 دو برابر = 8 9223372036854775800.00 */

چنین برنامه‌ای قبلاً در بخش توسعه داده شده است، اما در آنجا تمام اطلاعات مربوط به انواع داده‌ها به دستگاه خروجی استاندارد خروجی می‌شد و ما باید برنامه را دوباره بسازیم تا اطلاعات در یک فایل نوشته شود. برای انجام این کار، باید فایل را در حالت نوشتن، با کوتاه کردن اولیه اطلاعات فایل فعلی باز کنید ( خط 14). هنگامی که فایل ایجاد شد و با موفقیت باز شد (خطوط 16 - 20)، به جای عبارت cout، در خط 22از شی fout استفاده کنید بنابراین، به جای یک صفحه، اطلاعات مربوط به انواع داده ها در یک فایل نوشته می شود.

// write_file.cpp: نقطه ورودی برنامه کنسول را تعریف می کند. #include "stdafx.h" #include #عبارتند از // کار با فایل های #include // دستکاری کننده های ورودی/خروجی با استفاده از فضای نام std; int main(int argc, char* argv) (setlocale(LC_ALL, "rus"); // شیء را به فایل پیوند دهید، در حالی که فایل را در حالت نوشتن باز می کنید، ابتدا تمام داده ها را از آن حذف می کنید fout("data_types.txt "، ios_base::out | ios_base::trunc؛ اگر (!fout.is_open()) // اگر فایل باز نشده باشد (cout<< "Файл не может быть открыт или создан\n"; // напечатать соответствующее сообщение return 1; // выполнить выход из программы } fout << " data type " << "byte" << " " << " max value "<< endl // عناوین ستون <<"bool = " << sizeof(bool) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных bool*/ << (pow(2,sizeof(bool) * 8.0) - 1) << endl << "char = " << sizeof(char) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных char*/ << (pow(2,sizeof(char) * 8.0) - 1) << endl << "short int = " << sizeof(short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных short int*/ << (pow(2,sizeof(short int) * 8.0 - 1) - 1) << endl << "unsigned short int = " << sizeof(unsigned short int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned short int*/ << (pow(2,sizeof(unsigned short int) * 8.0) - 1) << endl << "int = " << sizeof(int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных int*/ << (pow(2,sizeof(int) * 8.0 - 1) - 1) << endl << "unsigned int = " << sizeof(unsigned int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных unsigned int*/ << (pow(2,sizeof(unsigned int) * 8.0) - 1) << endl << "long int = " << sizeof(long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных long int*/ << (pow(2,sizeof(long int) * 8.0 - 1) - 1) << endl << "unsigned long int = " << sizeof(unsigned long int) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных undigned long int*/ << (pow(2,sizeof(unsigned long int) * 8.0) - 1) << endl << "float = " << sizeof(float) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных float*/ << (pow(2,sizeof(float) * 8.0 - 1) - 1) << endl << "long float = " << sizeof(long float) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных long float*/ << (pow(2,sizeof(long float) * 8.0 - 1) - 1) << endl << "double = " << sizeof(double) << " " << fixed << setprecision(2) /*вычисляем максимальное значение для типа данных double*/ << (pow(2,sizeof(double) * 8.0 - 1) - 1) << endl; fout.close(); // программа больше не использует файл, поэтому его нужно закрыть cout << "Данные успешно записаны в файл data_types.txt\n"; system("pause"); return 0; }

غیرممکن است که متوجه نباشید که تغییرات در برنامه بسیار کم است و همه به لطف این واقعیت است که ورودی/خروجی استاندارد و ورودی/خروجی فایل دقیقاً به یک شکل استفاده می‌شوند. در پایان برنامه،خط 45ما به صراحت فایل را بسته ایم، اگرچه این مورد نیاز نیست، اما این یک برنامه برنامه نویسی خوب محسوب می شود. شایان ذکر است که تمام توابع و دستکاری‌های مورد استفاده برای قالب‌بندی ورودی/خروجی استاندارد برای ورودی/خروجی فایل نیز مرتبط هستند. بنابراین، هیچ خطایی در هنگام اپراتور رخ ندادکوت با یک شی جایگزین شده استمبارزه کردن

آخرین به روز رسانی: 31.10.2015

دو کلاس برای کار با دایرکتوری ها در فضای نام System.IO طراحی شده اند: Directory و DirectoryInfo.

کلاس دایرکتوری

کلاس Directory تعدادی روش ثابت برای مدیریت دایرکتوری ها ارائه می کند. برخی از این روش ها عبارتند از:

    CreateDirectory(path): یک دایرکتوری در مسیر مشخص شده ایجاد می کند

    Delete(path): دایرکتوری در مسیر داده شده را حذف می کند

    Exists(path): تعیین می کند که آیا دایرکتوری در مسیر مشخص شده وجود دارد یا خیر. اگر وجود داشته باشد true، اگر نباشد false را برمی‌گرداند.

    GetDirectories(path): لیستی از دایرکتوری ها را در مسیر دریافت می کند

    GetFiles(path): لیستی از فایل ها را در مسیر دایرکتوری دریافت می کند

    انتقال (sourceDirName، destDirName): دایرکتوری حرکت می کند

    GetParent(path): پوشه والد را دریافت کنید

کلاس DirectoryInfo

این کلاس قابلیتی را برای ایجاد، حذف، جابجایی و سایر عملیات دایرکتوری فراهم می کند. از بسیاری جهات شبیه دایرکتوری است. برخی از خواص و روش های آن عبارتند از:

    Create(): یک دایرکتوری ایجاد می کند

    CreateSubdirectory(path): یک زیر شاخه در مسیر مشخص شده ایجاد می کند

    Delete(): یک دایرکتوری را حذف می کند

    ویژگی Exists: تعیین می کند که آیا دایرکتوری وجود دارد یا خیر

    GetDirectories(): لیستی از دایرکتوری ها را دریافت می کند

    GetFiles(): لیستی از فایل ها را دریافت کنید

    MoveTo(destDirName): دایرکتوری را جابجا می کند

    ویژگی والد: دریافت دایرکتوری والد

    ویژگی ریشه: دریافت دایرکتوری ریشه

بیایید نمونه هایی از استفاده از این کلاس ها را بررسی کنیم

دریافت لیستی از فایل ها و زیر شاخه ها

string dirName = "C:\\"; if (Directory.Exists(dirName)) (Console.WriteLine("Subdirectories:"); string dirs = Directory.GetDirectories(dirName); foreach (رشته ها در dirs) (Console.WriteLine(s)؛ ) Console.WriteLine( Console.WriteLine("Files:")؛ فایل های رشته ای = Directory.GetFiles (dirName)؛ foreach (رشته ها در فایل ها) (Console.WriteLine(ها)؛ ))

به استفاده از اسلش در نام فایل ها توجه کنید. یا از یک اسلش دوتایی استفاده می کنیم: "C:\\" یا تک، اما علامت @ را در جلوی کل مسیر قرار می دهیم: @"C:\Program Files"

یک دایرکتوری ایجاد کنید

مسیر رشته = @"C:\SomeDir"; رشته فرعی = @"program\avalon"; DirectoryInfo dirInfo = new DirectoryInfo(path); if (!dirInfo.Exists) ( dirInfo.Create(); ) dirInfo.CreateSubdirectory(subpath);

ابتدا بررسی می کنیم که آیا چنین دایرکتوری وجود دارد، زیرا اگر وجود داشته باشد، امکان ایجاد آن وجود نخواهد داشت و برنامه خطا می دهد. در نتیجه مسیر زیر را دریافت خواهیم کرد: "C:\SomeDir\program\avalon"

دریافت اطلاعات در مورد دایرکتوری

string dirName = "C:\\Program Files"; DirectoryInfo dirInfo = DirectoryInfo جدید (dirName); Console.WriteLine($"نام دایرکتوری: (dirInfo.Name)"); Console.WriteLine($"نام کامل دایرکتوری: (dirInfo.FullName)"); Console.WriteLine($"زمان ایجاد دایرکتوری: (dirInfo.CreationTime)"); Console.WriteLine($"Root Directory: (dirInfo.Root)");

حذف یک دایرکتوری

اگر به سادگی متد Delete را روی یک پوشه غیر خالی که حاوی هر فایل یا زیر شاخه ای است اعمال کنیم، برنامه با خطا مواجه می شود. بنابراین، باید یک پارامتر نوع بولی اضافی را به متد Delete ارسال کنیم، که نشان می دهد پوشه باید با تمام محتویات آن حذف شود:

رشته dirName = @"C:\SomeFolder"; امتحان کنید ( DirectoryInfo dirInfo = DirectoryInfo جدید(dirName)؛ dirInfo.Delete(true); Console.WriteLine ("Directory deleted")؛ ) catch (Exception ex) (Console.WriteLine(ex.Message); )

رشته dirName = @"C:\SomeFolder"; Directory.Delete(dirName, true);

انتقال دایرکتوری

string oldPath = @"C:\SomeFolder"; string newPath = @"C:\SomeDir"; DirectoryInfo dirInfo = new DirectoryInfo(oldPath); if (dirInfo.Exists && Directory.Exists(newPath) == false) (dirInfo.MoveTo(newPath)؛ )

هنگام جابجایی، باید در نظر داشته باشیم که دایرکتوری جدیدی که می خواهیم تمام محتویات دایرکتوری قدیمی را به آن منتقل کنیم، نباید وجود داشته باشد.

برای سهولت در کار، اطلاعات در دستگاه های ذخیره سازی به صورت فایل ذخیره می شود.

فایل یک ناحیه نامگذاری شده از حافظه خارجی است که برای ذخیره آرایه ای از داده ها اختصاص داده شده است. داده های موجود در فایل ها از متنوع ترین ماهیت هستند: برنامه هایی به زبان الگوریتمی یا ماشین. داده های اولیه برای عملکرد برنامه ها یا نتایج اجرای برنامه؛ متون دلخواه; گرافیک و غیره

دایرکتوری (پوشه، دایرکتوری) - مجموعه ای با نام از بایت ها در یک رسانه ذخیره سازی حاوی نام زیر شاخه ها و فایل ها، که در سیستم فایل برای ساده سازی سازماندهی فایل ها استفاده می شود.

سیستم فایلبخشی کاربردی از سیستم عامل است که عملیات روی فایل ها را ارائه می دهد. نمونه هایی از سیستم های فایل عبارتند از FAT (FAT - جدول تخصیص فایل، جدول تخصیص فایل)، NTFS، UDF (مورد استفاده در سی دی ها).

سه نسخه اصلی FAT وجود دارد: FAT12، FAT16 و FAT32. آنها در بیتی بودن رکوردها در ساختار دیسک متفاوت هستند، یعنی. تعداد بیت های اختصاص داده شده برای ذخیره شماره خوشه. FAT12 عمدتا برای فلاپی دیسک (تا 4 کیلوبایت)، FAT16 برای دیسک های کوچک، FAT32 برای درایوهای فلش با ظرفیت بالا (تا 32 گیگابایت) استفاده می شود.

ساختار فایل سیستم را با استفاده از FAT32 به عنوان مثال در نظر بگیرید.

ساختار فایل FAT32

دستگاه های حافظه خارجی در سیستم FAT32 بایت نیستند، بلکه آدرس دهی را مسدود می کنند. اطلاعات در یک دستگاه حافظه خارجی در بلوک ها یا بخش ها نوشته می شود.

بخش - حداقل واحد آدرس پذیر ذخیره سازی اطلاعات در دستگاه های ذخیره سازی خارجی. به طور معمول، اندازه بخش در 512 بایت ثابت است. برای افزایش فضای آدرس دستگاه های حافظه خارجی، بخش ها در گروه هایی به نام خوشه ها ترکیب می شوند.

یک خوشه مجموعه ای از چندین بخش است که می تواند به عنوان یک واحد مستقل با ویژگی های خاص در نظر گرفته شود. ویژگی اصلی یک خوشه اندازه آن است که در تعداد بخش ها یا تعداد بایت ها اندازه گیری می شود.

فایل سیستم FAT32 ساختار زیر را دارد.

خوشه های مورد استفاده برای نوشتن فایل ها از 2 شماره گذاری می شوند. به عنوان یک قاعده، خوشه شماره 2 توسط دایرکتوری ریشه استفاده می شود و با شروع از خوشه شماره 3، آرایه داده ذخیره می شود. بخش‌هایی که برای ذخیره اطلاعات در بالای فهرست اصلی استفاده می‌شوند، خوشه‌بندی نشده‌اند.
حداقل اندازه فایل روی دیسک 1 کلاستر است.

بخش بوت با اطلاعات زیر شروع می شود:

  • EB 58 90 - شعبه و امضای بدون قید و شرط؛
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 00 02 - تعداد بایت ها در بخش (معمولا 512)؛
  • 1 بایت - تعداد بخش ها در خوشه.
  • 2 بایت - تعداد بخش های یدکی.

علاوه بر این، بخش بوت حاوی اطلاعات مهم زیر است:

  • 0x10 (1 بایت) - تعداد جداول FAT (معمولاً 2)؛
  • 0x20 (4 بایت) - تعداد بخش های روی دیسک.
  • 0x2C (4 بایت) - شماره خوشه دایرکتوری ریشه.
  • 0x47 (11 بایت) - برچسب حجم.
  • 0x1FE (2 بایت) - امضای بخش بوت (55 AA).

بخش اطلاعات سیستم فایل شامل:

  • 0x00 (4 بایت) - امضا (52 52 61 41)؛
  • 0x1E4 (4 بایت) - امضا (72 72 41 61)؛
  • 0x1E8 (4 بایت) - تعداد خوشه های آزاد، -1 در صورت ناشناخته بودن.
  • 0x1EC (4 بایت) - تعداد آخرین خوشه ثبت شده.
  • 0x1FE (2 بایت) - امضا (55 AA).

جدول FAT حاوی اطلاعاتی در مورد وضعیت هر خوشه روی دیسک است. 2 بایت پایین جدول FAT F8 FF FF 0F FF FF FF FF را ذخیره می کند (مطابق با حالت خوشه های 0 و 1، از نظر فیزیکی وجود ندارد). علاوه بر این، وضعیت هر خوشه حاوی تعداد خوشه‌ای است که فایل فعلی در آن ادامه دارد یا اطلاعات زیر:

  • 00 00 00 00 - خوشه رایگان است.
  • FF FF FF 0F پایان فایل فعلی است.
  • 8 بایت - نام فایل.
  • 3 بایت - پسوند فایل.

دایرکتوری ریشه شامل مجموعه ای از رکوردهای اطلاعات 32 بیتی برای هر فایل است که حاوی اطلاعات زیر است:

هنگام کار با نام فایل های طولانی (از جمله نام های روسی)، نام فایل در سیستم رمزگذاری UTF-16 کدگذاری می شود. در این حالت 2 بایت برای رمزگذاری هر کاراکتر اختصاص داده می شود. در این حالت نام فایل به شکل ساختار زیر نوشته می شود:

  • دنباله 1 بایت؛
  • 10 بایت شامل 5 کاراکتر پایینی نام فایل است.
  • ویژگی 1 بایت؛
  • 1 بایت رزرو شده است.
  • 1 بایت - جمع کنترلی نام DOS.
  • 12 بایت شامل 3 کاراکتر پایینی نام فایل است.
  • 2 بایت - تعداد اولین خوشه.
  • کاراکترهای باقی مانده از نام طولانی

کار با فایل ها در C

برای برنامه نویس، یک فایل باز به عنوان دنباله ای از داده ها در حال خواندن یا نوشتن نمایش داده می شود. هنگامی که یک فایل باز می شود، با آن مرتبط می شود جریان ورودی/خروجی. اطلاعات خروجی در جریان نوشته می شود، اطلاعات ورودی از جریان خوانده می شود.

هنگامی که یک جریان برای I/O باز می شود، با ساختار استاندارد نوع FILE که در stdio.h تعریف شده است، مرتبط می شود. ساختار FILE حاوی اطلاعات لازم در مورد فایل است.

باز کردن یک فایل با استفاده از تابع ()fopen انجام می شود که یک اشاره گر را به ساختاری از نوع FILE برمی گرداند که می تواند برای عملیات بعدی روی فایل استفاده شود.

FILE *fopen(نام، نوع)؛


name نام فایلی است که باید باز شود (شامل مسیر)
type یک اشاره گر به رشته ای از کاراکترها است که نحوه دسترسی به فایل را مشخص می کند:
  • "r" - فایل باز برای خواندن (فایل باید وجود داشته باشد)؛
  • "w" - یک فایل خالی برای نوشتن باز کنید. اگر فایل وجود داشته باشد، محتویات آن از بین می رود.
  • "a" - باز کردن فایل برای نوشتن تا انتها (برای پیوست)؛ اگر فایل وجود نداشته باشد ایجاد می شود.
  • "r+" - فایل باز برای خواندن و نوشتن (فایل باید وجود داشته باشد).
  • "w+" - یک فایل خالی برای خواندن و نوشتن باز کنید. اگر فایل وجود داشته باشد، محتویات آن از بین می رود.
  • "a+" - فایل را برای خواندن و اضافه کردن باز کنید، اگر فایل وجود نداشته باشد، ایجاد می شود.

مقدار بازگشتی یک اشاره گر به جریان باز است. اگر خطایی پیدا شد، NULL برگردانده می شود.

تابع fclose() استریم یا استریم های مرتبط با فایل های باز شده با ()fopen را می بندد. جریانی که باید بسته شود با آرگومان تابع fclose() تعیین می شود.

مقدار بازگشتی: مقدار 0 اگر جریان با موفقیت بسته شد. ثابت EOF در صورت بروز خطا.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#عبارتند از
int main() (
FILE *fp;
char name = "my.txt" ;
if ((fp = fopen (نام، "r" )) == NULL)
{
printf( "فایل باز نشد");
getchar();
بازگشت 0;
}
// فایل باز شد
... // اقدامات لازم روی داده ها
fclose(fp);
getchar();
بازگشت 0;
}

خواندن یک کاراکتر از یک فایل:

char fgetc(stream);


آرگومان تابع یک اشاره گر به جریانی از نوع FILE است. تابع کد کاراکتر خوانده شده را برمی گرداند. اگر به پایان فایل رسید یا خطایی رخ داد، ثابت EOF برگردانده می شود.

نوشتن یک کاراکتر در یک فایل:

fputc (شخصیت، جریان)؛

آرگومان های تابع یک کاراکتر و یک اشاره گر به جریانی از نوع FILE هستند. تابع کد کاراکتر خوانده شده را برمی گرداند.

توابع fscanf() و fprintf() مشابه توابع scanf() و printf() هستند، اما روی فایل های داده کار می کنند و نشانگر فایل را به عنوان اولین آرگومان خود دارند.

fscanf(stream، "InputFormat"، args);