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

عقبة بعد إنتقالي من ال Vb إلى السي ++

بدأه High volt في 28 يونيو 2008 · 12 رد · 1,155 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

السلام عليكم ورحمة الله وبركاته, ,,,

انتقلت حديثا من الفيجوال بيسك 6.0 إلى الـ سي ++ .

لدي برنامج كنت قد اعددته سلفا في الفيجوال بيسك, و حولت كوده إلى كود سي++, وقد عمل الكود بشكل سليم.

المشكلة, أن البرنامج في الفيجوال بيسك كانت مهمته إنشاء ملفات من نسق اعددته, وكانت البيانات المدخلة في الملفات هي متغيرات من النوع type :

Private Type Sounds
    filename As String
    Looping As Boolean
End Type

طبعا عند استيراد الملف, يجب ان يتم تحميل الملف في متغير من نقس النوع الذي تم تخزينه, لذا في السي عندما حولته كان المتغير :

struct Sounds
{
    char* filename;
    bool Looping;
};

الخطأ الذي ينتج لي هو قيم غريبة لم ادخلها سلفا عندما استورد الملف, علما بأنني استخدمت طريقة binary في التحميل والتخزين, واني قد جربت LPSTR بدلا من char*

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

تم تعديل هذه المشاركة بواسطة High volt في 28 يونيو 2008 في 10:24

#2

وعليكم السلام ورحمه الله وبركاته,

هل يمكنك وضع كود تحميل الملف الذي إعطاك القيم الغريبة؟ وإلا فإني لن استطيع المساعدة.

كذلك هنالك نقطة مهمة اود ان اذكرها, إستخدامك لـ char* من دون تثبيت الحجم قد يكون سبب المشكلة, كيف تعرف طول النص بالضبط الموجود في الملف؟ خاصة وإنك تستخدم binary mode.

كحل سريع لتلك المشكلة يمكنك إضافة قيمة جديدة رقمية في الهيكل Sounds تسبق النص لتبين حجم النص بالضبط (عدد حروفه), ثم تستخدم هذه القيمة عند القراءة.

#3

عندما حفظت الملفات هل تحفظها في الملف بطول ثابت هل استخدمته عند القراءة؟

tvquran_6.gif

#4

نعم أخي فهد.

أخي SandHawk:

اقتباس
هنالك نقطة مهمة اود ان اذكرها, إستخدامك لـ char* من دون تثبيت الحجم قد يكون سبب المشكلة, كيف تعرف طول النص بالضبط الموجود في الملف؟ خاصة وإنك تستخدم binary mode.

لا, ليس سبب المشكله (اختبرت ذلك).

وبالنسبة للكود, للحفظ :

bool SaveDB(Sounds *s) {
  std::ofstream fout("1.dat", ios_base::out | ios_base::binary | ios_base::trunc);

  if (!fout.is_open())
	return false;

  fout.write((const char*)s, sizeof(Sounds));
  fout.close();
  return true;
}

أما للقراءة:

bool LoadDB(Sounds *s) {

	std::ifstream fin("1.dat", ios_base::in | ios_base::binary);

  if (!fin.is_open())
	return false;
  fin.read((char*)s, sizeof(Sounds));
  fin.close();
  return true;
}

أظن ان الحل يكمن في استخدام نفس المتغير المستخدم في الحفظ, في الحفظ استخدمت متغير من النوع string (وذلك في الفيجوال بيسك), ولكن للقراءة لم اجد المتغير المناسب المماثل لـ string, ماذا ترون؟

#5

جربه بهذه الطريقه

struct Sounds
{
    char filename[512];
    bool Looping;
};

اعتقد مقاس النص في الفجول بيسك 512 بايت

tvquran_6.gif

#6

هممم, بعد تجربة صغيرة عملية بإستخدام الكود الذي وضعته, أدركت شيئاً فاتني ولا اعرف كيف.... وهو بالتأكيد ما سبب لك المشكلة...

لاحظ الهيكل الذي تستخدمه:

struct Sounds
{
	char* filename;
	bool Looping;
};

انت تقوم بحمل النص بإستخدام مؤشر, لاحظ كذلك إن الملف الناتج صغير الحجم جداً,... والآن أين المشكلة؟ إن الكود لا يقوم بخزن النص نفسه وإنما قيمة المؤشر!

لماذا إذن يعمل عند خزن وتحميل الملف من داخل الـ ++C؟ والجواب هو لأن المحتوى الذي يشير إليه المؤشر لم يتغير.

الحل؟ إستخدام دالة write مباشرة ليست فكرة صائبة, حيث إنك ليست لديك تحكم بما تفعله من الداخل, من الأفضل إستخدام دالة متخصصة لإخراج الكتل النصية للعنصر filename وأخرى لإخراج العنصر Looping.

أما عند القراءة فإستخدم الدوال المعاكسة تماماً :)

#7

الشكر الجزيل لكم اخوتي فهد وساند هاوك, حللتها حل مؤقت وغير عملي ولكن يفي بالغرض مؤقتا, وذلك بأن احجز مساحه ثابته في كل من الفيجوال بسيسك(الحفظ) والسي++ (القراءة), وذلك عن طريق وضع * وعدد الأحرف, وهذا ما كنت اجهله عن الفيجوال بيسك:

filename As String * 10

أخي فهد, جربت ان احجز 512 حرف في السي قياسا بقياس المتغير في الفيجوال بيسك, للأسف لم تفلح الطريقة, حيث ان حجم المتغير في الفيجوال يتغير حسب طول سلسلة الأحرف. ستكون طريقه فعاله لولا التغيير الحاصل حسب عدد الأحرف.

وبالنسبة لحلك أخي SandHawk , فهمت ما ترمي إليه وبإذن الله غدا سأنفذه.

تحياتي.

تم تعديل هذه المشاركة بواسطة High volt في 28 يونيو 2008 في 20:41

#8

مرحبا ,

اقتباس
انت تقوم بحمل النص بإستخدام مؤشر, لاحظ كذلك إن الملف الناتج صغير الحجم جداً,... والآن أين المشكلة؟ إن الكود لا يقوم بخزن النص نفسه وإنما قيمة المؤشر!

لماذا إذن يعمل عند خزن وتحميل الملف من داخل الـ ++C؟ والجواب هو لأن المحتوى الذي يشير إليه المؤشر لم يتغير.

لا حول ولا قوة الا بالله, كلام سليم 100% , فاتت علي.

في التطبيق, كان هناك اكثر من خطأ, الخطأ الأول وهو عدم تماثل المتغيرات بين اللغتين, لذا وجدت الحل في هذه المقالة, لكن الخطأ الثاني يكمن في ان طبيقة التطبيق هي أن احفظ مصفوفة ديناميكية في الملف,

هذا ما كتبته للحفظ:

Sounds* s;
fin.read((char*)s, sizeof(Sounds));

ولكن ردك أخي كان لي بالمرصاد :happy: :

اقتباس
انت تقوم بحمل النص بإستخدام مؤشر

, لذا: كيف لي أن احفظ مصفوفة ديناميكيه في ملف ؟ وأشكر لكم اهتمامكم.

تم تعديل هذه المشاركة بواسطة High volt في 29 يونيو 2008 في 17:47

#9

بما إنك ترغب في خزن او تحميل نص ديناميكي, فيجب ان تكون هنالك طريقة لمعرفة حجمه أو على الأقل أين ينتهي.

سأقترح طريقتان جربهما عسى ان يقوموا بالمهمة, الأولى هي إضافة متغير يسبق النص يبين حجم النص المحفوظ بالضبط, يمكن ان تستخدم الدالة strlen للحصول على تلك القيمة, ثم تستخدم القيمة عند قراءة النص.

والثانية اعتقد إنها افضل, بما أن كل نص يعرف مباشرة في داخل ++C يضاف إليه رمز '0\' والذي يمثل نهاية النص (يسمى النص حينها بالـ null terminated string) يمكنك إستخدام هذا الرمز لمعرفة أين ينتهي النص بالضبط, وبما إنك تستخدم الـ streams فإن معامل '<<' يستطيع القيام بذلك تلقائياً (قراءة النص حتى يصل إلى الـ null), بهذا الشكل تقريباً:

// When saving
fout.write(s->filename, strlen(s->filename)+1); // this will write the filename and it's null ('\0')
...
// When reading first read to a temporary buffer
char buffer[255];
fin>>buffer; // this will read the text with the null
s->filename = new  char[strlen(buffer)+1];
strcpy(s->filename, buffer);
// don't forget to delete s->filename when you are done
...

(لاحظ إضافة واحد على القيمة التي تعيدها strlen, ذلك لأن strlen لا تحسب رمز الـ null كجزء من طول النص.)

أتمنى ان اكون ساعدت, وانا حاضر لأي إستفسارات اخرى :)

تم تعديل هذه المشاركة بواسطة SandHawk في 30 يونيو 2008 في 12:05

#10

شكرا جزيلا لك أخي, ما قصرت بارك الله فيك, أقصد مصفوفة ديناميكيه من النوع struct وفي هذه الحالة: مصفوفة ديناميكيه من النوع sounds (مصفوفة غير محددة العناصر).

#11

في حالة مصفوفة ديناميكية من Sounds (أو عموماً مجموعات البيانات بإختلافها), فأعتقد إن الحل يكمن في تطبيق ما يسمى بالـ file header, حيث يقسم الملف إلى جزئين, الأول يسمى الـ header ويحتوي معلومات مهمة عن بيانات الملف, في هذه الحالة فإنه سيحتوي على عدد هياكل الـ Sounds المخزونة في الملف بالضبط (بصورة رقم) إضافة إلى أي بيانات مشتركة أخرى, ولكن.. يجب أن يكون حجم الـ header معروف وثابت, يلي هذا الجزء مباشرة جزء الـ data حيث يحتوي على هياكل Sounds نفسها مخزونة بالتعاقب.

لقراءة الملف المخزون بهذه الصورة تبدأ اولاً بقراءة الـ header بالكامل وإستخراج المعلومات التي تحتاجها لتحميل البيانات, ثم تقرأ تلك البيانات.

هذه الطريقة مستخدمة في 90% من الملفات التي هي من نوع binary, مثلاً في ملفات الصور يحتوي الـ header على طول وعرض الصورة, عمق الألوان, وبيانات اساسية أخرى مثل نوع الضغط المستخدم... إلخ.

#12

شكرا جزيلا لك أخي وجعلها الله في موازين حسناتك, ما قصرت, نعم, رأيت الطريقة عندما كنتت استورد ملفات MD2 أيام الفيجوال بيسك, سأعتمد الطريقة بإذن الله.

تم تعديل هذه المشاركة بواسطة High volt في 2 يوليو 2008 في 10:40

#13

السلام عليكم

على حسب معلوماتي المتواضعة انه بعد تعريف المتغير Sounds ، فانه يجب انشاء object من هذا المتغير ثم كتابته 100 مره مثلا او على حسب العدد المطلوب.

هل هذه الطريقة صحيحة ؟

او انها تستهلك مساحة في القرص الصلب من غير فائدة؟ ومالحل؟

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

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

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

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

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