PDA

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



mohamad1370
چهارشنبه 02 مرداد 1392, 00:00 صبح
این سوال تووی انجمن زیاد پرسیده شده ولی من جواب قانع کننده ایی پیدا نکردم
من می خوام محتویات یک فایل رو بخونم (توسط یک تابع) و محتویات خونده شده رو تووی یه آرایه یا یه اشاره گر توسط تابع برگردونم و ازش استفاده کنم .
اما مشکل من کجاست . فرض کنید من یک فایل حاوی متن زیر دارم :

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

تووی فایل های من تعداد خط معنی نداره یعنی چی ؟یعنی اینکه جمله مهمه و ممکنه یک جمله مثل دو خط اول هر کدوم یک خط باشن یا مثل جمله سوم تووی چندین خط .منم همونطور که گفتم هربار می خوام جمله ها رو بخونم و استفاده کنم نه خط چطور تووی فایل جمله رو بخونم ؟فرض کنید وسط فایل که نمیدونم خط چندومه بخوام یه جمله رو که معلوم نیست چند خطه رو بخونم چطور میشه اینکار رو کرد .ابتدا و انتهای هر جمله رو میشه با یک کارکتر مشخص کرد یا یک عدد? مثلاً بتونم جمله 100 ام رو تووی فایل بخونم .
اما اینکه گفتم تعداد فایل ها و نامشون نامشخصه منظورم اینه که کاربر مشخص می کنه از کدوم فایل و کدوم خط رو نیاز داره .
بر فرض من 100 تا فایل دارم که متن همه اشون مشخصه و تعداد جمله های مشخص ولی طول هر جمله با هم متفاوته .می خوام کاربر اگه خواست جمله 5 ام فایل 20 ام رو بتونه بخونه .

حالا اینکار امکان پذیره ؟اگه آره ممنون میشم راه حلش رو هم بگید.

mohamad1370
پنج شنبه 03 مرداد 1392, 00:01 صبح
این همه بازدید دریغ از یه راهنمایی :ناراحت:

مصطفی ساتکی
پنج شنبه 03 مرداد 1392, 10:08 صبح
اینکه فایل ها زیاد هستند و اسم فایل نا مشخص هرکاری می کنم تابع open متغیری که از نوع string تعریف کردم رو که قراره نام فایل داخلش ذخیره بشه رو قبول نمی کنه

سوالتو اینقدر گنگ پرسیدی بایستی سوالتو ویرایش کنی یا مدیرا سوالتو پاک کنن به خاط همینه کسی جواب نمی ده.
اینکه فایل ها زیاد هستند و اسم فایل ها نامشخص یعنی چی؟ .مگه اسم فایل نام مشخص هم داریم در نهایت می تونستی بگی اسم فایل به صورت temp تعییم میشه تابع open چیه؟نگه منظورت fopen هستش اگر string رو میخای به پارامتر char* پاس بدی بایستی از متد c_str استفاده کنید.
اصلا مشخص نمی کنید متن شما utf یا ansi ؟ با کد زیر می تونید ansi بنویسید برای utf هم بایستی از توابع با پیشوند w استفاده کنید.
#include <fstream>
using namespace std;
int main()
{
std::ofstream file_out("file_name.txt");
file_out << "line1" << endl;
file_out << "line2" << endl;
file_out.close();


std::ifstream filein("file_name.txt");
std::string line;
while ( std::getline(filein, line) )
std::cout << line << std::endl;

}

mohamad1370
پنج شنبه 03 مرداد 1392, 19:21 عصر
پست اول رو ویرایش کردم

منظورم از تابع open تابع عضو کلاس fstream .
در مورد متن داخل فایلها هم متن پارسی داره هم انگلیسی البته جدا از هم هستند

mohamad1370
پنج شنبه 03 مرداد 1392, 23:50 عصر
چطور جمله n ام رو مشخص کنم و بخونم
اگه این محتویات فایل من باشه



محمد دنبال راهی برای خواندن متن از فایل است.
محمد نمی داند باید از چه روشی استفاده کند.
این متن خیلی طولانی است بیش از یک خط .................................................. .................
.
.
جمله 20 (بیستم )................................
جمله 21 ....................................
.
.
.
جمله 100 ام........................


من می خوام جمله 20 ام رو بخونم چطور بفهمم جمله 20 ام کدوم یک از جمله های منه با فرض اینکه انتهای همه جمله های با یک کارکتر مثلا (".") مشخص شده ؟

به نظرم میشه ابتدای همه جمله ها رو با یه چیزی مثلا یک عدد مشخص کرد .جمله 20 ام میشه شماره 20 سرچ کنه هرجایی به 20 رسید اونجا ابتدای جمله بیستم ولی مشکل اینجاست اگه فایل هزارتا جمله داشته باشه و هر جمله 10 خط باشه کلی زمان هدر میره .مخصوصاً اگه جمله های پایانی بخواد خونده بشه

مصطفی ساتکی
جمعه 04 مرداد 1392, 00:40 صبح
ا
انتهای هرجمله باید با به نشونه ی خاص مشخص بشه .
مثلا با کاراکتر '.' .
اول شما باید Offset فایل رو که در اون لحظه هستید داخل یک متغییر نگه دارید و تا زمانی که به کاراکتر انتهای جمله (برای مثال '.' ) رسیدید تعداد بایت های پیمایش شده رو بشمارید . اونوقت طول جمله رو بدست میاری .
بعد با طول بدست اومده یک Block توی Heap درست میکنی و میری به Offset شروع و بایت ها رو تا Offset پایانی (یعنی انتهای جمله) میخونی ،‌و داخل Block ذخیره میکنی .
خیلی سادست . فقط باید معلوم بشه که Encoding فایلت چیه .
اصلاً نیاز به همچین کاری ندارند می تونن به روش معمول هر خط را با '\n' جدا کنند یا هر جدا کننده دیگر و سپس تابع getline که در بالا مثالش را قرار دادم من پارامتر سوم را پاس ندادم و همان مقدار پیش فرض یعنی enter را قبول کردم شما پارامتر اول file stream رو میدید پارامتر دوم خود wstring و پارامتر سوم جداکننده و هر وقت تابع صفر برگردوند یعنی دیگه خطی در فایل وجود نداره
برای خواندن 10 خط هم خودتون شمارنده تعریف کنید و شمارنده به مقدار مورد نظر رسید خواندن را خاتمه بدید.
در مثال بالا ofstream را به wofstream و string را به wstring تغییر بدید میشه همون چیزی که مد نظر شماست البته برای درست خواندن نیاز به اعمال local هم دارید .
به این صورت:

std::locale defaultLocale(""); // from machine config
std::wfstream file;
file.imbue(defaultLocale);

مصطفی ساتکی
جمعه 04 مرداد 1392, 00:54 صبح
اولاً که جمله همیشه کوچکتر از یک خط هستش ثانیاً آن پارامتر سوم را برای همین قرار دادن که شما جدا کننده مد نظر تون را مشخص کنید. به این روش به همان اندازه جمله حافظه می گیره بعلاوه جداکننده .
برای سرعت خواندن هم بایستی میزان بافر fstream را با متد rdbuf مشخص کنید .
موفق باشید.

مصطفی ساتکی
جمعه 04 مرداد 1392, 01:12 صبح
خدا خیرت بده دفعه پیشم گفتی از stl استفاده نمی کنی تعجب کردم کارها با همان performance قبلی ولی خیلی آسانونتر شده با stl.
کلاس پایه stream از کلاس streambuf جهت buffer استفاده می کنه.

mohamad1370
جمعه 04 مرداد 1392, 03:13 صبح
مثلا میتونی با یه سری اطلاعات اولیه اینکار رو بهتر انجام بدی .
مثل این

[Count] = 2
[Offsets] 0,8
[Sentences]
Hello.
abcdefg.


فایلت شبیه به این بشه .
بعد از قسمت [Offsets] یه آرایه ای از Offset وجود داره که Offset شروع هر جمله رو توی فایل نشون میده .
نسبت به درخواست شماره ی جمله ، از تو آرایه Offset اون جمله رو برمیداری و سر میپری به اون Offset و جمله رو میخونی .

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

شاید اینکاری که گفتید خوب باشه ولی وقتی تعداد فایل ها زیاده حدود و هر فایل ممکنه تا 200 تا جمله (پاراگراف بگیم درست تره! :لبخند:) داشته باشه چطور آفست هر پاراگراف رو در بیارم و تووی آرایه آفست ذخیره کنم؟





اصلاً نیاز به همچین کاری ندارند می تونن به روش معمول هر خط را با '\n' جدا کنند یا هر جدا کننده دیگر و سپس تابع getline که در بالا مثالش را قرار دادم من پارامتر سوم را پاس ندادم و همان مقدار پیش فرض یعنی enter را قبول کردم شما پارامتر اول file stream رو میدید پارامتر دوم خود wstring و پارامتر سوم جداکننده و هر وقت تابع صفر برگردوند یعنی دیگه خطی در فایل وجود نداره
برای خواندن 10 خط هم خودتون شمارنده تعریف کنید و شمارنده به مقدار مورد نظر رسید خواندن را خاتمه بدید.
در مثال بالا ofstream را به wofstream و string را به wstring تغییر بدید میشه همون چیزی که مد نظر شماست البته برای درست خواندن نیاز به اعمال local هم دارید .
در حال حاضر مشکل اصلی من یونیکد نیست بلکه مشکل اصلی خوندن از مکان مشخصی از فایله (پاراگراف 100 ام فایل).
همونطور که میگید با تابع getline میشه هر مقدار رو که می خوایم از فایل بخونیم و با یک کارکتر انتهای فایل رو مشخص کنیم ولی چطور ابتدای پاراگرافها رو تشخیص بدیم و اینکه چطور چندمین پاراگرافها رو تعیین کنیم که کاربر بتونه پارگراف مورد نظرش رو بخونه یا کل پاراگرافهای بعد از پاراگراف nام؟

UfnCod3r
جمعه 04 مرداد 1392, 09:36 صبح
جمله رو با نقطه مشخص می کنن دیگه شما ی حلقه بزار که دو نه دونه کاراکتر ها رو بخونه به نقطه که رسیدی پایان جملست بعد از نقطه قبلی تا نقطه جدید می شه جمله
برای اینکه نصف جملت ممکنه تو خط بعد باشه بگرد و اگه کاراکتر 'n\' داخل جمله بود برش دار. همین .:لبخندساده:

UfnCod3r
جمعه 04 مرداد 1392, 09:52 صبح
بیا اینم ی نمونه ی ساده

char fileContent[] = "asdasd234234. qwe23234234. rdfg 345 ttdrgdge t56e e544 et 5t retert.";
int fileLen = strlen(fileContent);
int seek = 0;
int jomleIndex = 0;
while(seek != fileLen)
{
if(fileContent[seek] == '.')
{
fileContent[seek] = '\0';
printf("%s\n", fileContent + jomleIndex);
jomleIndex = seek + 1;
}

seek++;
}

مصطفی ساتکی
جمعه 04 مرداد 1392, 10:04 صبح
در حال حاضر مشکل اصلی من یونیکد نیست بلکه مشکل اصلی خوندن از مکان مشخصی از فایله (پاراگراف 100 ام فایل).
همونطور که میگید با تابع getline میشه هر مقدار رو که می خوایم از فایل بخونیم و با یک کارکتر انتهای فایل رو مشخص کنیم ولی چطور ابتدای پاراگرافها رو تشخیص بدیم و اینکه چطور چندمین پاراگرافها رو تعیین کنیم که کاربر بتونه پارگراف مورد نظرش رو بخونه یا کل پاراگرافهای بعد از پاراگراف nام؟
خوب پاراگراف بعد از هر enter شکل می گیره میشه همان '\n' باید تعدادشون بشماری تا حد دلخواه برسه .
نکته: کار آسونیه زیاد سخت می گیری

mohamad1370
یک شنبه 06 مرداد 1392, 19:23 عصر
همه حرفهای شما درست بر فرض بنده یه تابع نوشتم که فایل رو باز کرد و خط به خط اونو با دستور

getline(Inpute_File , Line ,'\n');

بخونه

حالا شما به من بگید این خوندن یه جایی باید ذخیره بشه که قابل استفاده بشه یا نه مثل یه آرایه از نوع string اگه بخوایم برنامه رو اصولی بنویسیم نباید این ارایه از نوع پویا باشه که کنترلش دست خودمون باشه ؟
بعد هم درسته هر بار که با دستور بالا پاراگراف رو خوندیم میشه تعدادشون رو شمرد ولی نمیدونم چطور از آفستها استفاده کنم

string* FileRead()
{
str1 = new string[???];
int i ;
Inpute_File.open(File_Name.c_str() ,ios::in );
if(Inpute_File.is_open())
{
while(!Inpute_File.eof())
{
getline(Inpute_File , Line ,'\n');
str1[i] = Line ;
Number_Paragraph++ ;

}
Inpute_File.close();
Amount_Paragraph = new int[Number_Paragraph];
for( i = 0 ; i < Number_Paragraph ; i++ )
{
Amount_Paragraph[i] = str1[i].length();
}

}
else
return 0;

return str1;

خلاصه بگم کاربر باید بتونه این سه تا کار رو انجام بده
1-یک پاراگراف مشخص رو بخونه مثلا تعیین کنه پارگراف 20
2-از یک پارگراف مشخص شروع به خوندن بکنه تا هرجایی که خواست از 20 به بعد
2- از یک پاراگراف تا یک پاراگراف دیگه به طور مثال از 20 تا 30

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

mohamad1370
سه شنبه 08 مرداد 1392, 18:41 عصر
چطور از آفستها استفاده کنم
این تیکه کد اندازه هر پاراگراف رو میده خیلی راحت میشه آفست ابتدای هر پارگراف رو به دست اورد فقط نمی دونم چطور از آفست مورد نظر بخونم

MyFile.open("file.txt",ios::in);
begin = MyFile.tellg();
for (int i = 0 ; i < 200 ; i++ )
{
getline(MyFile , mm ,'\n');
MyFile.seekg(0 ,ios::cur);
end = MyFile.tellg();
Amount_Par[i] = end -begin ;
begin = end ;

}