منبع اصلی نوشتار زیر در این لینک قرار دارد

آموزش فایل در سی پلاس پلاس

file in c++

یکی از بیشترین سوال هایی که توی نظرات سایت مطرح می شود کار با فایل در ++C  است به همین دلیل در این پست به فایل ها در سی پلاس پلاس می پردازیم.

در سی پلاس پلاس دو نوع فایل می توان ساخت:

  1. فایل متنی : در این فایل تمام اطلاعات به صورت کاراکتر و ذخیره می شود.
  2. فایل باینری (bin): اطلاعات به همان شکلی که در حافظه هستند در فایل ذخیره می شوند.

همین طور برای کار با فایل سه حالت داریم:

  1. in : در این حالت اطلاعات از فایل خوانده می شود.
  2.  out : در این حالت اطلاعات به فایل فرستاده می شود و در آن دخیره می شود.
  3. out & in : هم زمان در فایل هم می نویسیم و هم می از آن می خوانیم.

دسترسی به اطلاعات در فایل ها به دو صورت است

  1. ترتیبی : یعنی اطلاعات پشت سره هم در فایل نوشته می شود یا اطلاعات پشت سر هم از فایل خوانده می شود.
  2. تصادفی : در این روش با استفاده از کلید خاصی مستقیم به سراغ رکورد مورد نظر در فایل می رویم.

دو نوع اطلاعات رو هم می شود در فایل ریخت:

  1. نوع داده های ابتدایی مانند : int , float , char , ….
  2. نوع داد های که خودمان تعریف کرده ایم مانند : class , struct

نکته: در سی پلاس پلاس می توان همه ی نوع داده ها را در فایل ذخیره کرد ولی بعضی ها نوع داده را با ساختمان داده هایی همچون map و غیره اشتباه می گیرند. یک ساختمان داده را نمی توان یک جا در فایل ریخت بلکه باید تک تک اجزایش را در فایل ریخت یا از فایل خواند.

هر بار که یک فایل برای نوشتن باز می کنیم دو حالت رخ می دهد:

  1. یک فایل جدید ایجاد می شود ,به طور پیش فرض این حالت رخ می دهد . اگر فایل با آن اسم وجود نداشته باشد یکی ایجاد می کند اگر چنین فایلی موجود باشد آن را از اول می نویسد و همه ی اطلاعات قبلی در آن را پاک می کند.
  2. می توان در ادامه یک فایل نوشت , اگر فایل موجود نباشد یکی ایجاد می کند و اگر فایل موجود باشد می رود در ادامه ی فایل می نویسد که برای این کار می توان از ios::app استفاده کرد.

 

ایجاد یک شی برای فایل ها:

برای کار کردن با فایل ها باید شی از کلاس ifstream (برای خواندن اطلاعات) و یا ofstream (برای نوشتن اطلاعات) به شکل زیر بسازیم.

برای ساخت یک شی از کلاس ifstream (برای خواندن اطلاعات) به شکل رو به رو عمل می کنیم:

ifstream myObjectName( nameOfFile, flag);

myObjectName : اسم شی از کلاس ifstream است  که می خواهید بسازید.

nameOfFile : اسم فایل است , که یک رشته است یا متغییر رشته ای مانند:

ifstream fp("my file.txt", flag);

یا

string nameOfFile = "my File.dat";

ifstream myObjectName( nameOfFile, flag);

flag : نوع فایل  و طریقه خواندن را مشخص می کند.

ifstream myObjectName( "my file.txt", ios::in | ios::binary);

مثلا در فایل بالا دو flag زیر که با “|” از هم جدا شده اند قرار دارد.

ios::in : می گوید شی جهت خواندن از فایل ایجاد شده است.

ios::binary : می گوید فایل از نوع باینری است.

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

 

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

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

#include <fstream>	//file header

تو این قسمت می خواهیم یک برنامه ساده بنویسیم که سه بار یک اسم و نمره ی اون فرد را بخواند و در فایل بریزد.ابتدا باید یک فایل را ایجاد کنیم. در کد زیر یک شی از جریان خروجی فایل باز کرده ام:

// define write file stream
	ofstream outputFile("output.dat", ios::out);

 

outputFile : اسم شی ای از کلاس جریان خروجی فایل است.

“output.dat” : اسم فایلی است که ایجاد کرده ام.

نکته : از آن جایی که در قسمت اول “output.dat” را نوشته ام به طور پیشفرض فایل در محلی که برنامه قرار دارد ایجاد می شود . برای این که فایلی در مسیر دلخواه داشته باشیم به جای “output.dat” باید مثلا بنویسیم

“D:My programming codeoutput.dat”

با این کار مسیر پیشفرض ایجاد فایل تغییر می کند.

ios::out : نشان می دهد شی که ساخته شده جهت نوشتن در فایل است.

همیشه بعد از ساخت یک شی از کلاس ifstream و ofstream باید چک کنیم و ببینیم که فایل درست باز شده است یا نه در غیر این صورت ممکن است برنامه ادامه پیدا کند و در عملکرد برنامه مشکل رخ دهد بدون اینکه خطای کامپایلری و یا زمان اجرا گرفته شود.برای چک کرذن ساده ترین کار شکل زیر است :

//check for file opening
	if ( !outputFile)
	{
		cerr << "some thing wrong during opening file!" << endl;
		exit(1);
	}

فرض کنید متغییر رشته ای name  و متغییر اعشاری score را داریم برای چاپ آن در خروجی تصویری یا صفحه نمایش چه می کنیم ؟ مثلا از cout به شکل زیر استفاده می کنیم :

cout << name << " " << score << endl;

حالا می خواهید name و score را در فایل متنی outputFile که ایجاد کرده اید بنویسید , تنها کاری که لازم است بکنید جای گذاری cout با شی از جریان خروجی فایل (ofstream) است که آن شی در این مثال outputFile  است , به شکل زیر :

outputFile << name << " " << score << endl;

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

// write in text file.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <fstream>	//file header
#include <string>

using namespace std;

int main( )
{
	float score;
	string name;

	// define write file stream
	ofstream outputFile("output.dat", ios::out);

	//check for file opening
	if ( !outputFile)
	{
		cerr << "some thing wrong during opening file!" << endl;
		exit(1);
	}

	//get information 3 time
	for (int i = 0; i < 3; i++)
	{
		cout << "Enter Name: ";
		//getline(cin, name);
		cin >> name;

		cout << "Enter score: ";
		cin >> score;
		cout << endl;

		//write in file
		outputFile << name << " " << score << endl;
	}

	return 0;
}

 

ورودی که من به برنامه دادم :

input 1

فایلی که در محل اجرای پروژه ایجاد شده :

make file in c++

محتویات درون فایل وقتی آن را با Nodepad باز کردم:

content of file

 

خواندن از فایل متنی :

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

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

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

// define object of read file stream
	ifstream inputFile("output.dat", ios::in);

inputFile : نام شی ای است که از جریان ورودی فایل ساخته ایم.

“output.dat” : اسم فایلی است که می خواهیم محتویاتش را بخوانیم.

ios::in : نشان می دهد که فایل را جهت خواندن اطلاعات باز کرده ایم.

بعد از ایجاد شی جریان ورودی فایل مانند قسمت قبل باید چک کنیم ببینیم که فایل باز شده است یا نه بعد برنامه را ادامه دهیم ، با کد زیر این کار را انجام می دهیم:

//check for file opening
	if (!inputFile)
	{
		cerr << "some thing wrong during opening file!" << endl;
		exit(1);
	}

برای خواندن یک نام و یک نمره از صفحه کلید چه می کنیم ؟ مشخصا از cin به شکل زیر استفاده می کنیم:

cin >> name >> score;

برای خواندن یک فایل باید cin را با یک شی از کلاس ورودی فایل جایگزین کنیم ، که این شی ما در این جا inputFile نام دارد. پس برای خواندن یک اسم و نمره اش باید این کار را کنیم :

inputFile >> name >> score;

چیز های ضروری همین ها بودند . در زیر برنامه ای را می بینید که فایل مورد نظر را باز می کند و سه نام را همرا نمرشان می خواند و چاپ می کند.

// read text file
//

#include "stdafx.h"
#include <iostream>
#include <fstream>	//file header
#include <string>

using namespace std;

int main()
{
	float score;
	string name;

	// define object of read file stream
	ifstream inputFile("output.dat", ios::in);

	//check for file opening
	if (!inputFile)
	{
		cerr << "some thing wrong during opening file!" << endl;
		exit(1);
	}

	//get information 3 time
	for (int i = 0; i < 3; i++)
	{
		//read name from file
		inputFile >> name;
		//read score from file	
		inputFile >> score;
		
		//print name and score in terminal
		cout << name << " , " << score << endl;
	}

	return 0;
}

خروجی برنامه و اطلاعات درون فایل را در شکل زیر می بینید.output1

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

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

// define object of write file stream
	ofstream outputFile("output.dat", ios::out | ios::binary);

ios::binary : نشان می دهد که فایلمان از نوع باینری است . حالا می خواهیم یک عدد اعشاری را در یک فایل باینری بنویسیم ، برای نوشتن در فایل باینری از تابع عضو write استفاده می کنیم:

//write in binary file
		outputFile.write(reinterpret_cast<char *>(&num), sizeof(float));

reinterpret_cast :آدرس متغییری را که به آن پاس می کنیم را به صورت char * در می آورد.

sizeof(float : تعداد بایت های یک نوع داده را مشخص می کند ، متغییر num از نوع float است ، با sizeof(float می گوییم که متغییری که داریم باهاش کار می کنیم به این اندازه حافظه اشغال می کند .

در برنامه ی زیر یک فایل باینری را باز می کنیم و سه عدد اشاری در آن می ریزیم :

// writing in binary file.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <fstream>	//file header
#include <string>

using namespace std;

int main()
{
	float num;


	// define object of write file stream
	ofstream outputFile("output.dat", ios::out | ios::binary);

	//check for file opening
	if (!outputFile)
	{
		cerr << "some thing wrong during opening file!" << endl;
		exit(1);
	}

	//get information 3 time
	for (int i = 0; i < 3; i++)
	{
		
		cout << "Enter float number : ";
		cin >> num;
		cout << endl;

		//write in binary file
		outputFile.write(reinterpret_cast<char *>(&num), sizeof(float));

	}

	return 0;
}

ورودی که من داده ام :

input 2

 

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

content of file 2

خواندن از فایل باینری :

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

برای خواندن یک فایل باینری باید یک شی از کلاس ورودی فایل ایجاد کنم :

ifstream inputFile("output.dat", ios::in | ios::binary);

ios::binary : نشان می دهد فایل از نوع باینری است .

فرض کنید یک عدد اعشاری را می خواهم از فایل بخوانم ، برای خواندن از فایل باینری از از دستور read به شکل زیر استفاده می کنیم :

inputFile.read(reinterpret_cast<char *>(&num), sizeof(float));

sizeof(float : می گوید به اندازه ی یک متغییر اعشاری از فایل بخوان و مقدار خواندخ شده را در num  قرار بده.

در برنامه ی زیر سه عدد باینری نوشته شده در فایل باینری سری قبل را از فایل می خوانیم و چاپ می کنیم :

// reading from binary file.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <fstream>	//file header
#include <string>

using namespace std;

int main()
{
	float num;
	string name;

	// define object of read file stream
	ifstream inputFile("output.dat", ios::in | ios::binary);

	//check for file opening
	if (!inputFile)
	{
		cerr << "some thing wrong during opening file!" << endl;
		exit(1);
	}

	//get information 3 time
	for (int i = 0; i < 3; i++)
	{
		//read score from file	
		inputFile.read(reinterpret_cast<char *>(&num), sizeof(float));

		//print name and score in terminal
		cout << num << endl;
	}

	return 0;
}

 

نوشتن و خواندن اطلاعات اشیای کلاس :

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

۲ – کل شی را یکجا در یک فایل باینری بریزیم ، دقیقا مانند کاری که با عدد اعشاری در بالا کردیم.

نوشتن و خواندن رشته ها در فایل باینری :

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

// testtest.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

int main()
{
	char *buf;
	string str1 = "abababab";
	string str2 = "wjwjwjwjwjwj";
	string str3 = "vivivivivivivivi";

	int size1 = (str1.size());
	int size2 = (str2.size());
	int size3 = (str3.size());

	ofstream output("output.txt", ios::out | ios::binary);
	if (!output)
	{
		cout << "can't open file" << endl;
		exit(1);
	}

	output.write(reinterpret_cast<char *>(&size1), sizeof(int));
	output.write(str1.c_str(), size1);

	output.write(reinterpret_cast<char *>(&size2), sizeof(int));
	output.write(str2.c_str(), size2);

	output.write(reinterpret_cast<char *>(&size3), sizeof(int));
	output.write(str3.c_str(), size3);

	str1 = str2 = str3 = "";
	size1 = size2 = size3 = 0;

	output.flush();
	output.close();
	//=======================================================================
	ifstream input("output.txt", ios::in | ios::binary);
	if (!output)
	{
		cout << "can't open file" << endl;
		exit(1);
	}

	input.read(reinterpret_cast<char *>(&size1), sizeof(int));
	buf = new char[size1];
	input.read(buf, size1);
	str1.assign(buf, size1);


	input.read(reinterpret_cast<char *>(&size2), sizeof(int));
	buf = new char[size2];
	input.read(buf, size2);
	str2.assign(buf, size2);

	input.read(reinterpret_cast<char *>(&size3), sizeof(int));
	buf = new char[size3];
	input.read(buf, size3);
	str3.assign(buf, size3);

	cout << str1 << endl << str2 << endl << str3 << endl << endl;

	return 0;
}

 

باقیمانده ی نوشته را در روزهای آینده کامل می کنم.

Digg This  Reddit This  Stumble Now!  Buzz This  Vote on DZone  Share on Facebook  Bookmark this on Delicious  Kick It on DotNetKicks.com  Shout it  Share on LinkedIn  Bookmark this on Technorati  Post on Twitter  Google Buzz (aka. Google Reader)  



برچسب ها : , , ,