28 – حفظ الملفات Saving Files

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد : حفظ الملفات Saving Files

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

سوف نتعلم في هذا الدرس مايلي:

  • الاختيار بين التخزين الداخلي او الخارجي choose internal or external Storage
  • الحصول على الصلاحيات الازمة للتخزين الخارجي Obtain Permissions for External Storage
  • حفظ ملف على تخزين داخلي Save file on internal storage
  • حفظ ملف على تخزين خارجي Save file on External storage
  • الاستعلام عن المساحة الفارغة Query free space
  • حذف ملف Delete a File

يفضل الاطلاع على  موضوع “خيارات التخزين Storage Options”

يستخدم نظام اندرويد نظام ملفات file system  مشابه لنظام الملفات في النظم المكتبية او اية منصات عمل اخرى.

يوصف لنا هذا الدرس كيفية العمل مع نظام ملفات اندرويد بهدف قراءة وكتابة الملفات عبر استخدام واجهات الملفات File APIs.

إن غرض File  مناسب لقراءة وكتابة كميات كبيرة من المعطيات بترتيب ( البداية –إلى – النهاية) بدون تخطي الترتيب. على سبيل المثال, هذا الاسلوب مناسب فيما يخص ملفات الصور او أي شيء يتم تبادله عبر الانترنت.

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

يفترض الدرس بأن على اطلاع باساسيات نظام الملفات بلينوكس , بواجهات file input/output APIs ضمن java.io.

الاختيار بين التخزين الداخلي والتخزين الخارجي choose internal or external storage

تحوي كل اجهزة اندرويد على منطقتي تخزين خاصة بالملفات: “تخزين داخلي internal” و “تخزين خارجي External storage”.

جاءت هذه التسميات من الأيام الاولى لاندرويد, حيث كانت اغلب التجهيزات تقدم ذاكرة مستقرة مدمجة مع الجهاز (التخزين الداخلي ), بالاضافة إلى وسيط تخزين يمكن ازالته مثل “بطاقة الذاكرة الرقمية SD card” (التخزين الخارجي ).

قسمت بعض الاجهزة مساحة التخزين الدائم إلى موضعي “داخلي internal ” و “خارجي external” , وبذلك حتى في حال عدم وجود وسيط تخزين قابل للازالة , يكون لدينا مساحتي تخزين مختلفتين , ويكون ايضا سلوك واجهات التطبيقات البرمجية API واحدا سواء كان التخزين الخارجي قابل للازالة اولا.

القائمة التالية تخلص الحقائق حول كل من مساحتي التخزين:

 التخزين الداخلي Internal Storage

  • متاح دوما
  • الملفات التي تخزن هنا تكون متاحة فقط لتطبيقك بشكل افتراضي
  • عندما يزيل المستخدم تثبيت تطبيقك, يقوم النظام بازالة كل ملفات التطبيق من التخزين الداخلي.

يعتبر التخزين الداخلي افضل خيار عندما ترغب بالتاكد من عدم تمكن كل من التطبيقات الاخرى والمستخدم من النفاذ إلى ملفاتك.

التخزين الخارجي External storage

  • لا يكون متاح دوما , لأن المستخدم قد يشبكا التخزين الخارجي على شكل USB , وقد يزيله  في بعض الحالات من الجهاز.
  • يمكن قراءته من الوسط الخارجي word-readable , وبذلك فإن الملفات المحفوظة هنا يمكن قرائتها بشكل خارج عن سيطرتك.
  • عندما يقوم المستخدم بإزالة تثبيت تطبيقك, يقوم عندها النظام بازالة ملفات تطبيقك فقط في حال كنت قد حفظتهم ضمن مسار من مسارات getExternalFilesDir().

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

تنويه: بالرغم من ان التطبيقات يتم تثبيتها على التخزين الداخلي internal storage بشكل افتراضي, ولكن بإمكانك ان تحدد من خاصية android:installLocationضمن ملف manifest مكان التثبيت , وبالتالي من الممكن تثبيت تطبيقك على التخزين الخارجي external storage.

يقدر المستخدمون جدا هذا الخيار عندما يكون حجم الا APK كبير جدا , ويكون لديهم مساحة تخزين خارجي اكبر من مساحة التخزين الداخلي. لمزيد من المعلومات بالامكان الاطلاع على App Install Location.

 الحصول على الصلاحيات اللازمة للتخزين الخارجي Obtain permissions for external storage

لكي تكتب ضمن التخزين الخارجي external storage , يتوجب عليك طلب صلاحية WRITE_EXTERNAL_STORAGEضمن ملف

manifest.

<manifest …>
<uses-permission android:name=”android.permission.WRITE_EXTERNAL_STORAGE” />

</manifest>

تنبيه : حاليا , تملك كل التطبيقات امكانية القراءة ضمن التخزين الخارجي بدون الحاجة إلى صلاحيات خاصة.

على كل الاحوال, هذا سوف يتغير في المستقبل القريب في الاصدارات المستقبلية.في حال احتاج تطبيقك للقراءة من التخزين الخارجي external storage ( بدون الكتابة عليه), عندها سوف تحتاج للتصريح عن الصلاحية READ_EXTERNAL_STORAGE. والآن , ولكي تضمن ان يعمل تطبيقك كما هو متوقع , يتوجب عليك التصريح عن هذه الصلاحية الآن , وقبل ان تاخذ التطويرات المستقبلية مكانها المزعوم.

 

<manifest …>
<uses-permission android:name=”android.permission.READ_EXTERNAL_STORAGE” />

</manifest>

على كل الاحوال, في حال استخدم تطبيقك صلاحية WRITE_EXTERNAL_STORAGE, عندها فإنه بشكل ضمني يملك الصلاحية للقراءة من التخزين الخارجي.

لا تحتاج اية صلاحيات لحفظ الملفات على الخزين الداخلي internal storage. يملك تطبيقك دوما الصلاحية لقراءة وكتابة الملفات ضمن مسار الخزين الداخلي لديه.

حفظ الملف على التخزين الداخلي save a File on internal storage

عندما تقوم بتخزين ملف على التخزين الداخلي , بإمكانك الحصول على المسار المناسب “كملف” عبر استدعاء احد التابعين التاليين:

getFilesDir() يعيد ملف File  يمثل المسار الداخلي لتطبيقك.

getCacheDir()يعيد ملف File  يمثل المسار الداخلي لملفات الكاش المؤقتة لتطبيقك. تأكد من حذف كل ملف ما ان يصبح غير ضروريا. لانه في حال وقع النظام في حالة بطىء اثناء عمله على التخزين , عندها فمن الممكن ان يحذف ملفات الكاش لديك بدون ان يقم بتنبيهك.

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

على سبيل المثال:

File file = new File(context.getFilesDir(), filename);

بشكل بديل , بإمكانك استدعاء التابع openFileOutput()للحصول على FileOutputStream  الذي يقوم بدوره بكتابة الملف ضمن مسارك الداخلي. على سبيل المثال, فيما يلي مثال لآلية كتابة بعض النصوص ضمن ملف:

String filename = “myfile”;
String string = “Hello world!”;
FileOutputStream outputStream;

try {
outputStream = openFileOutput(filename, Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}

او , في حال رغبت بحفظ بعض الملفات ضمن الكاش, يجب ان تستخدم التابع createTempFile()بدلا من ذلك. على سبيل المثال, يقوم التابع التالي باستخلاص اسم الملف من عنوان ما URL وينشأ ملف بنفس الاسم ضمن مسار الكاش الداخلي ضمن تطبيقك:

public File getTempFile(Context context, String url) {
File file;
try {
String fileName = Uri.parse(url).getLastPathSegment();
file = File.createTempFile(fileName, null, context.getCacheDir());
catch (IOException e) {
// Error while creating file
}
return file;
}

ملاحظة : يتم تحديد مسار التخزين الداخلي ضمن تطبيقك app’s internal directory من قبل اسم حزمة تطبيقك ضمن موقع محدد ضمن نظام ملفات اندرويد.

بشكل تقني, فإن اي تطبيق اخر يستطيع قراءة ملفاتك الداخلية في حال اسندت نمط الملف file mode إلى “قابل للقراءة” readable. على كل الاحوال, فإن بقية التطبيقات الاخرى تحتاج ايضا إلى معرفة اسم حزمة تطبيقك app package name واسم الملف file name.  لا تستطيع بقية التطلبيقات استعراض المسارات الداخلية , وكلك لا تملك إمكانية النفاذ بهدف القراءة او الكتابة مالم تصرح عن ذلك بشكل صريح عبر وضع الملفات قابلة للقراءة اوالكتابة.

اذن, مادامت تستخدم MODE_PRIVATE  لملفاتك فيما يخص التخزين الداخلي, عندها لا تستطيع التطبيقات الاخرى الوصول إليها.

حفظ الملف على التخزين الخارجي save a file on external storage

بما ان التخزين الخارجي ليس متاح دوما- مثل الحالة التي يشبك فيها المستخدم بطاقة الذاكرة SD card او يزيلها – لذلك يتوجب عليك دوما التحقق من ان التخزين الخارجي متاح دوما قبل النفاذ اليه.

بإمكانك الاستعلام عن حالة التخزين الخارجي عبر استدعاء التابع getExternalStorageState() .في حال كانت الحالة المعادة تساوي MEDIA_MOUNTED , عندها بإمكانك قراءة وكتابة ملفاتك.

على سبيل المثال, تعتبر التوابع التالية مفيدة في تحديد فيما اذا كان التخزين متاحا:

 

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}

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

ملفات عامة Public files:

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

على سبيل المثال, الصور التي يتم التقاطها من قبل تطبيقك او الملفات التي يتم تحميلها.

ملفات خاصة Private files:

الملفات التي تعود بشكل قانوني إلى تطبيقك ويجب ان يتم حذفها عندما يقوم المستخدم بإزالة تثبيت تطبيقك.

بالرغم من انه يمكن الوصول إلى هذه الملفات – بشكل تقني – من قبل المستخدم وبقية التطبيقات الاخرى , وذلك بسبب كونها تقع ضمن التخزين الخارجي, ولكنها واقعيا لا تزود قيم للمستخدم خارج تطبيقك.

عندما يقوم المستخدم بإزالة تثبت تطبيقك, فإن النظام يقوم بحذف كل الملفات ضمن مسار الملفات الخارجي الخاصةapp’s External private directory  ضمن تطبيقك.

على سبيل المثال, الموارد الاضافية التي يتم تحميلها من قبل تطبيقك أو ملفات الوسائط المتعددة المؤقتة.

في حال رغبت بحفظ ملفات عامة ضمن التخزين الخارجي, استخدم التابع getExternalStoragePublicDirectory() للحصول على File  الذي يمثل المسار المناسب على التخزين الخارجي.

ياخذ هذا التابع معامل يحدد نوع الملف الذي ترغب بحفظه , وبذلك يصبح بإمكانك تصنيف الملفات بشكل منطقي مع بقية الملفات العامة, مثل DIRECTORY_MUSICأو DIRECTORY_PICTURESعلى سبيل المثال:

 public File getAlbumStorageDir(String albumName) {
// Get the directory for the user’s public pictures directory.
File file = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, “Directory not created”);
}
return file;
}

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

كل مسار يتم انشائه بهذه الطريقة تتم اضافته إلى المسار الاب الذي يغلف كل ملفات التخزين الخارجية الخاصة بتطبيقك, التي يقوم النظام بحذفها في حال قام المستخدم بإزالة تثبيت تطبيقك.

على سبيل المثال, فيما يلي تابع بإمكانك استخدامه لانشاء مسار لالبوم الصور الخاصة.

public File getAlbumStorageDir(Context context, String albumName) {
// Get the directory for the app’s private pictures directory.
File file = new File(context.getExternalFilesDir(
Environment.DIRECTORY_PICTURES), albumName);
if (!file.mkdirs()) {
Log.e(LOG_TAG, “Directory not created”);
}
return file;
}

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

تذكر , بأن التابع getExternalFilesDir()ينشأ مسار ضمن المسار الذي يقوم المستخدم بحذفه عندما يقوم بازالة تثبيت تطبيقك. في حال كانت الملفات التي تحفظها يجب ان تبقى بعد ازالة المستخدم للتطبيق – مثل في حال كان التطبيق عبارة عن كاميرا , وقد المستخدم يرغب بالاحتفاظ بالصور – عندها يتوجب ان تستخدم بدلا من ذاك التابع التابع  getExternalStoragePublicDirectory().

بغض النظر فيما اذا كنت تستخدم التابع getExternalStoragePublicDirectory()فيما يخص الملفات المشتركة أو التابع getExternalFilesDir()فيما يخص الملفات الخاصة بتطبيقك, فإنه من المهم عندها استخدام اسماء ملفات من تلك المزودة من قبل ثوابت API  مثل DIRECTORY_PICTURES.تؤكد اسماء المسارات هذه بأن هذه الملفات تعامل بالشكل الائق والمطلوب من قبل النظام.

على سبيل المثال, الملفات المحفوظة ضمن DIRECTORY_RINGTONESيتم تصنيفها من قبل النظام على انها نغمات بدل من موسيقا.

الاستعلام عن المساحة الفارغة query free space

في حال كنت تعمل مسبقا عن مقدار المعطيات التي ترغب بحفظها, بإمكانك عندها ان تعرف فيما اذا كانت المساحة المتوفرة كافية , ولن تسبب IOException  , وذلك عبر استدعاء getFreeSpace()أو getTotalSpace().

تزودنا هذه التوابع بمقدار المساحة المتاحة الحالية , والمساحة الاجمالية ضمن حجم التخزين, بالترتيب.

تعتبر هذه المعلومات ايضا مفيدة بهدف تجنب تعبئة حجم التخزين بكمية اكبر من الحد الاعلى المسموح به.

 على كل الاحوال, لا يضمن لك النظام بأنه بإمكانك كتابة القدر من البايتات ذاته المصرح عنه ضمن التابع getFreeSpace()على انه متاح.

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

ملاحظة : لا يتوجب عليك التحقق من المساحة الفارغة المتاحة قبل حفظ ملفاتك.

بإمكانك بدلا من ذلك محاولة كتابة الملف بشكل مباشر, ومن ثم تقوم ب catch ل IOException  في حال حدث خلل ما. قد تحتاج للقيام بذلك في حال لم تكن تعلم مسبقا ماهو مقدار المساحة التي قد تحتاجها. على سبيل المثال, في حال غيرت ترميز الملف قبل حفظه عبر تحويل صورة من نمط PNG إلى JPEG, عندها فلن تعلم مسبقا حجم الملف بعد التحويل.

حذف ملف Delete a file

يتوجب عليك دوما حذف الملفات التي لم تعد بحاجة لها.الطريقة المباشرة لحذف ملف هي ان تملك مرجع الملف المفتوح وتستدعي التابع delete()على ذاك المرجع.

  myFile.delete();

في حال كان الملف قد حفظ على تخزين داخلي, بإمكانك ايضا ان تسأل ال Context  بأن يجد لك الملف ويحذفه عبر استدعاء deleteFile():

myContext.deleteFile(fileName);

ملاحظة : عندما يقوم المستخدم بإزالة تثبيت تطبيقك, يقوم اندرويد بحذف مايلي:

  • ·         كل الملفات التي قمت بحفظها ضمن التخزين الداخلي
  • ·         كل الملفات التي قمت بحفظها على التخزين الخارجي باستخدام getExternalFilesDir().

على كل الاحوال, يتوجب عليك ان تقوم بحذف كل ملفات الكاش التي تم انشائها بواسطة التابع بشكل دائم, ويتوجب عليك ان تقوم بشكل نظامي بحذف بقية الملفات التي لم تعد بحاجة لها.

وعند هذا القدر نكتفي بهذه الحلقة ,وإلى لقاء قريب في حلقة قادمة تتحدث عن حفظ المعطيات ضمن قاعدة المعطيات

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته.

, , , , , , , , , , , , , , , , , , , , ,

  1. أضف تعليق

اترك رد

Please log in using one of these methods to post your comment:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s

%d مدونون معجبون بهذه: