الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

[ تمت الإجابة ]سؤال : كيف أحذف أو أعدل في ملف ؟

مغلقمُجاب
بدأه yassinislam في 27 فبراير 2013 · 7 رد · 3,631 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته اخوتي جزاكم الله خيرا 

 

انا الان في صدد عمل برنامج صغير بالسي ++  واريد تخزين المعلومات في ملف 

لحد الان الامور جيدة 

المشكل الذي طرح عندي هو  كيفية حذف وتعديل  في الملف  

لهذا اود من المتخصيي مد يد المساعدة في حل هذه الاشكالية 

وجزاكم الله خيرا 

#2

لحذف الملف يمكنك استدعاء remove :

  

#include <cstdio>

int main(int argc, char **argv)
{
    if( remove("file.txt") ) {
        perror("Error");
    }

    return 0;
}
 

تعيد صفر إذا حذف الملف.

 

بالنسبة لتعديل الملف فلم أفهم قصدك، يرجى توضيحه.

تم تعديل هذه المشاركة بواسطة Mr.B في 27 فبراير 2013 في 21:20

#3

شكرا اخي الحبيب على الرد 

 

مافهمتني 

مثلا عندي برنامج يدخل رقم تعريف الطالب واسمه و عمره 

 

انا اريد ان ادخل للبرنامج رقم الطالب والبرنامج يحذف لي من الملف  معلومات الطالب الاخرى 

 

 

اليك كود اضافة طالب 

 

struct etd{int code;char nom[10];};
struct etd e;
	ofstream w;
   w.open("test.txt",ios::out | ios::app);
   int n;
   cout<<"N:"<<endl;cin>>n;
   for(int i=0;i<n;i++)
   {
    cout<<"nom:";cin>>e.nom;
    cout<<"code:";cin>>e.code;
    w<<e.nom<<"\n"<<e.code<<endl;
}
   w.close();

تم تعديل هذه المشاركة بواسطة yassinislam في 27 فبراير 2013 في 23:00

#4

ستحتاج لإستخدام B-Tree لهذا الشان، ايضا ستحتاج لإستخدام مفهوم الـ Allocation unit.

 

 

و الله ولي التوفيق

مدونتي: C++ Tips and Tricks

#5

شكرا اخي  c++er
انا لا اتقن الداتا ستراكتر هل من حل سهل اخر 

#6

السلام عليكم ..

  1. (حسب معلوماتي) لا يوجد طريقة مباشرة لحذف سطر من ملف .. بل نقوم بقراءة الملف الأول سطر سطر .. و نقوم بكتابة الأسطر في ملف جديد ما عدا السطر الذي نزيد حذفه ثم نحذف الملف الأصلي و نسمي الملف الجديد باسم الملف الأصلي .. الكود في الرابط (delete-a-line-from-a-text-file) .
  2. (كود C) يمكن الكتابة فوق بينانات محددة في الملف باستخدام fseek  لنقل المؤشر للموقع المطلوب ثم نبدأ بكتابة البيانات الجديدة .. و لكن اعتقد أنه معقد قليلا . رابط .

لا إله إلا الله ... محمد رسول الله

لو كانت مشاركتي مفيدة و تريد تشجيعي على المزيد من العطاء , فضلا قم بتقييم المشاركة

المعرًف القديم : houssam11350_11350

من مواضيعي : ArabGenCode : مولد كود و إجراءات مخزنة و واجهات لجداول سيكوال سيرفر

#7 أفضل إجابة

هناك طريقة بسيطة واحترافية بعض الشيء (رايح تحصل على درجات إضافية لو كنت طالب إذا أحسنت تطبيقها) وهي أن تقوم بإنشاء صيغة ملف خاصة ببرنامجك. العملية جداً سهلة وأفضل من العمل مع ملف نصّي.

في برنامجك كل سجل طالب يحتوي على 3 معلومات:

* اسم الطالب.

* معرّفه.

* عمره.

أنشيء بنية تحتوي هذه المعلومات:

#define MAX_NAME 25

struct Record {
    char name[MAX_NAME+1]; // الواحد هذا لصّفر الذي في آخر النص
    unsigned short id;
    unsigned short age;
};
الآن إذا أردت إضافة طالب، املأ هذه البنية بمعلومات هذا الطالب:
Record record1;

memset(&record1, 0, sizeof(Record)); // صفّر البنية

header.records += 1;
strncpy(&record1.name[0], "Mr.B", MAX_NAME);
record1.id  = 1;
record1.age = 21;
ثمّ إكتبها مباشرة في الملف. وإذا أردت إضافة سجل آخر كرر نفس العملية واكتبه في الملف بعد هذا السجل.

الآن سيصبح شكل ملفك:

+-----------------+--------------+---------------+
| 26 bytes (name) | 2 bytes (id) | 2 bytes (age) | <- record 1
+-----------------+--------------+---------------+
| 26 bytes (name) | 2 bytes (id) | 2 bytes (age) | <- record 2
+-----------------+--------------+---------------+
| 26 bytes (name) | 2 bytes (id) | 2 bytes (age) | <- record 3
 .....
لمعرفة عدد السجلات التي يحتويها الملف من الأفضل أن تضيف رأس للملف header يحتوي رقم يبين عدد السجلات الموجودة:
struct FileHeader {
    unsigned int records;       // عدد السجلات
};
وتكتبه قبل أن تكتب السجلات للملف، برنامج بسيط:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

#define MAX_NAME 25

struct FileHeader {
    unsigned int records;       // number of student records
};

struct Record {
    char name[MAX_NAME+1];
    unsigned short id;
    unsigned short age;
};

int main(int argc, char **argv)
{
    // zero the memory
    FileHeader header;
    Record record1, record2;

    memset(&header, 0, sizeof(FileHeader));
    memset(&record1, 0, sizeof(Record));
    memset(&record2, 0, sizeof(Record));

    header.records += 1;
    strncpy(&record1.name[0], "Mr.B", MAX_NAME);
    record1.id  = 1;
    record1.age = 21;
    
    header.records += 1;
    strncpy(&record2.name[0], "yassinislam", MAX_NAME);
    record2.id  = 2;
    record2.age = 21;

    FILE *fh;
    
    if( (fh = fopen("file.db", "w")) == NULL ) {
        perror("Error");
        return -1;
    }

    // write header
    fwrite(&header, sizeof(FileHeader), 1, fh);
    // write first record
    fwrite(&record1, sizeof(Record), 1, fh);
    // write second record
    fwrite(&record2, sizeof(Record), 1, fh);

    fclose(fh);

    return 0;
}
بسيط. البرنامج سيولد ملف اسمه file.db لو فتحته ربما ستجد رموز غير مفهومة (ستظهر لديك لو فتحت الملف):
   Mr.B                        yassinislam
هذه البيانات الموجودة في البنية لكنها مخزنة كبيانات بدل نصوص، البيانات أسهل معالجة من النصوص كما سترى.

لقراءة الملف، قم بفتحه وإقرأ رأس الملف كي تعرف عدد السجلات:

FileHeader header;
...

fread(&header, sizeof(FileHeader), 1, fh);

cout << "File file.db has " << header.records << " record(s)" << endl; // سيطبع عدد السجلات
ولقراءة السجلات اعمل حلقة تكرار وأقرأ السجل في البنية:
for( i = 0 ; i < header.records ; i++ ) {
    fread(&record, sizeof(Record), 1, fh);
    cout << "Name: " << record.name << endl;
    cout << "ID  : " << record.id << endl;
    cout << "Age : " << record.age << endl << endl;
}
برنامج القراءة:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

#define MAX_NAME 25

struct FileHeader {
    unsigned int records;       // number of student records
};

struct Record {
    char name[MAX_NAME+1];
    unsigned short id;
    unsigned short age;
};

int main(int argc, char **argv)
{
    FileHeader header;
    Record record;
    FILE *fh;
    unsigned int i;
    
    if( (fh = fopen("file.db", "r")) == NULL ) {
        perror("Error");
        return -1;
    }

    // read the header
    fread(&header, sizeof(FileHeader), 1, fh);

    cout << "File file.db has " << header.records << " record(s)" << endl;

    for( i = 0 ; i < header.records ; i++ ) {
        fread(&record, sizeof(Record), 1, fh);
        cout << "Name: " << record.name << endl;
        cout << "ID  : " << record.id << endl;
        cout << "Age : " << record.age << endl << endl;
    }

    fclose(fh);

    return 0;
}
سيطبع:
File file.db has 2 record(s)
Name: Mr.B
ID  : 1
Age : 21

Name: yassinislam
ID  : 2
Age : 21
البرنامج قرأ الملف وعرف عدد السجلات وطبعها.

الآن مسألة حذف سجل، هناك حل بأنك تقرأ كافة السجلات وتخزّنها في مصفوفة سجلات Record وتحذف السجل من تلك المصفوفة ثم تعيد كتابتها الأ أنها متعبة لأن حذف عنصر من المصوفة يتطلب إزاحة shifting كامل المصفوفة لتأخذ مكان هذا العنصر:

+---------+---------+---------+---------+---------+---------+
| Record1 | Record2 | Record3 | Record4 | Record5 | Record6 | نريد حذف السجل رقم 3
+---------+---------+---------+---------+---------+---------+

+---------+---------+---------+<<<<<<<<<+<<<<<<<<<+<<<<<<<<<+
| Record1 | Record2 | XXXXXXX | Record4 | Record5 | Record6 |  نحتاج لأن نزيح السجلات 4 و 6 لليمين
+---------+---------+---------+<<<<<<<<<+<<<<<<<<<+<<<<<<<<<+

+---------+---------+---------+---------+---------+---------+
| Record1 | Record2 | Record4 | Record5 | Record6 |         | بعد الإزاحة
+---------+---------+---------+---------+---------+---------+
يمكن عمل هذا بإستخدام الدالة memmove الا أنها عملية متعبة (عليك وعلى البرنامج)، مثال على حذف سجل:
#include <iostream>#include <cstring>#include <cstdio>using namespace std;#define MAX_NAME 25struct FileHeader {    unsigned int records;       // number of student records};struct Record {    char name[MAX_NAME+1];    unsigned short id;    unsigned short age;};int main(int argc, char **argv){    FileHeader header;    Record record1 = {0}, record2  = {0}, record3  = {0};    Record recordArray[3]  = {0};    strncpy(&record1.name[0], "A", strlen("A"));    record1.id  = 1;    record1.age = 10;    strncpy(&record2.name[0], "B", strlen("B"));    record2.id  = 2;    record2.age = 10;    strncpy(&record3.name[0], "C", strlen("C"));    record3.id  = 3;    record3.age = 10;    /*    +-----+-----+-----+    |  A  |  B  |  C  |    +-----+-----+-----+    */    memcpy(&recordArray[0], &record1, sizeof(Record));    memcpy(&recordArray[1], &record2, sizeof(Record));    memcpy(&recordArray[2], &record3, sizeof(Record));    for( int i = 0 ; i < 3 ; i++ ) {        cout << recordArray.name << endl;    }    /*    +-----+-----+-----+    |  A  |  C  | 000 |    +-----+-----+-----+    */    memmove(&recordArray[1], &recordArray[2], sizeof(Record));    memset(&recordArray[2], 0, sizeof(Record));        cout << "-----------------------------------------" << endl;    for( int i = 0 ; i < 3 ; i++ ) {        cout << recordArray.name << endl;    }    return 0;    }
العمل مع المصفوفة ليس بتلك السهولة. هناك حل أسهل والشائع لمثل هذه المشكلة وهو أن تستخدم القوائم المتصلة linked list.

ماتحتاج إليه أن تنشئ عقدة عبارة عن بنية داخلها سجل ومؤشّر لعقدة آخرى:

struct RecordList {    Record record;    RecordList*next;};
إذا أردت إضافة عقدة، فقط تضيف مؤشرها للـnext (بإستثناء الأولى):
    // إضافة سجلات وربط العقد ببعض
    RecordList *recordList = new(RecordList);
    memcpy(&(recordList->record), &record1, sizeof(Record));

    recordList->next = new(RecordList);
    memcpy(&(recordList->next->record), &record2, sizeof(Record));

    recordList->next->next = new(RecordList);
    memcpy(&(recordList->next->next->record), &record3, sizeof(Record));

    // العقدة الأخيرة لاتشير لشيء
    recordList->next->next->next = NULL;
بعد تنفيذ هذا الجزء سيصبح شكلها في الذاكرة:
 RecordList       RecordList      RecordList
 +---------+     +---------+     +---------+
 | Record1 |  +->| Record2 |  +->| Record3 |  +->X
 +---------+  |  +---------+  |  +---------+  |
 |  next   |--+  |  next   |--+  | next    |--+
 +---------+     +---------+     +---------+
إذا أردت حذف عقدة، فقط حررها من الذاكرة وأعد ربط العقدة التي على اليمين بالتي تلي العقدة المحذوفة:
    // حذف العقدة الثانية
    RecordList *temp = recordList->next->next;
    delete recordList->next;
    recordList->next = temp;
بعد تحرير الذاكرة:
 RecordList                        RecordList
 +---------+                     +---------+
 | Record1 |  +->X               | Record3 |  +->X
 +---------+  |                  +---------+  |
 |  next   |--+                  | next    |--+
 +---------+                     +---------+
بعد الوصل:
 RecordList       RecordList
 +---------+     +---------+
 | Record1 |  +->| Record3 |
 +---------+  |  +---------+
 |  next   |--+  |  next   |
 +---------+     +---------+
البرنامج للتجربة:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

#define MAX_NAME 25

struct FileHeader {
    unsigned int records;       // number of student records
};

struct Record {
    char name[MAX_NAME+1];
    unsigned short id;
    unsigned short age;
};

struct RecordList {
    Record record;     // السجل
    RecordList *next;  // عقدة للسجل التالي
};

int main(int argc, char **argv)
{
    FileHeader header;
    Record record1 = {0}, record2  = {0}, record3  = {0};
    RecordList *recordList = NULL;

    strncpy(&record1.name[0], "A", strlen("A"));
    record1.id  = 1;
    record1.age = 10;

    strncpy(&record2.name[0], "B", strlen("B"));
    record2.id  = 2;
    record2.age = 10;

    strncpy(&record3.name[0], "C", strlen("C"));
    record3.id  = 3;
    record3.age = 10;

    // إضافة سجلات وربط العقد ببعض
    recordList = new(RecordList);
    memcpy(&(recordList->record), &record1, sizeof(Record));

    recordList->next = new(RecordList);
    memcpy(&(recordList->next->record), &record2, sizeof(Record));

    recordList->next->next = new(RecordList);
    memcpy(&(recordList->next->next->record), &record3, sizeof(Record));

    // العقدة الأخيرة لاتشير لشيء
    recordList->next->next->next = NULL;


    // طباعة كافة العقد
    RecordList *list = recordList;
    while( list ) {
        cout << list->record.name << endl;
        list = list->next;
    }

    // حذف العقدة الثانية
    RecordList *temp = recordList->next->next;
    delete recordList->next;
    recordList->next = temp;

    cout << "-----------------------------" << endl;

    list = recordList;
    while( list ) {
        cout << list->record.name << endl;
        list = list->next;
    }

    return 0;
    
}
الآن بعد حذف السجلات التي تريدها يمكنك المرور على كامل القائمة وكتابة السجلات في ملف.

هناك كثير من المواضيع حول القوائم المتصلة في النت (عربية وبالإنجليزية) ابحث عنها وتعلمها، تطبيقها سهل جداً.

ملاحظة: هناك أنواع من القوائم المتصلة، هذه تسمى queue linked list - طابور لأن العناصر تضاف من الأخير. هناك اسمه stack linked list - مكدس أسهل بعض الشيء في التطبيق.

2
#8

اخي M-bوالله مااعرف كيف اشكرك 

جزاك الله خيرا  استفدت منك كثيرا بارك الله فيك 

 

والشكر لك اخي حسام  على الفكرة  

هذا الموضوع مغلق.

مواضيع مشابهة

عدد الزوار حالياً

المتواجدون خلال آخر دقيقتين · يتحدّث كل ٣٠ ثانية

—الإجمالي—أعضاء مسجّلون—زوار بدون تسجيل

جارٍ التحقق من المتواجدين…