سؤال

لدي القليل من رمز Java الذي يخرج ملف XML إلى نظام ملفات مثبت على NFS. على خادم آخر يحتوي على ملفات FileyTem كمشاركة Samba ، هناك عملية تشغيل استطلاعات الرأي لملفات XML جديدة كل 30 ثانية. إذا تم العثور على ملف جديد ، يتم معالجته ثم إعادة تسميته كملف احتياطي. 99 ٪ من الوقت ، تتم كتابة الملفات بدون مشكلة. ومع ذلك ، يحتوي ملف النسخ الاحتياطي بين الحين والآخر على ملف مكتوب جزئيًا.

بعد بعض النقاش مع بعض الأشخاص الآخرين ، خمننا أن العملية التي تعمل على الخادم الخارجي تتداخل مع دفق إخراج Java عند قراءة الملف. اقترحوا أولاً إنشاء ملف من النوع. Temp الذي سيتم إعادة تسميته بعد ذلك إلى .xml بعد اكتمال كتابة الملف. ممارسة الصناعة المشتركة. بعد التغيير ، فشل إعادة تسمية في كل مرة.

أظهرت بعض الأبحاث أن ملف Java I/O هو عربات التي تجرها الدواب عند العمل مع NFS المثبتة على أنظمة الملفات.

ساعدني جافا معلمو! كيف يمكنني حل هذه المشكلة؟

فيما يلي بعض المعلومات ذات الصلة:

  • عملي هي Java 1.6.0_16 تعمل على Solaris 10
  • نظام الملفات المثبتة هو NAS
  • الخادم مع عملية الاقتراع هو نظام Windows Server 2003 R2 ، حزمة الخدمة 2

هنا عينة من الكود الخاص بي:

//Write the file
XMLOutputter serializer = new XMLOutputter(Format.getPrettyFormat());
FileOutputStream os = new FileOutputStream(outputDirectory + fileName + ".temp");
serializer.output(doc, os);//doc is a constructed xml document using JDOM
os.flush();
os.close();

//Rename the file
File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(fileName + ".xml");
boolean success = oldFile.renameTo(newFile);
if (!success) {
    // File was not successfully renamed.
    throw new IOException("The file " + fileName + ".temp could not be renamed.");
}//if
هل كانت مفيدة؟

المحلول

ربما يجب عليك تحديد المسار الكامل في اسم الملف الجديد:

File newFile = new File(outputDirectory + fileName + ".xml");

نصائح أخرى

هذا يبدو وكأنه خطأ بالنسبة لي:

File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(fileName + ".xml");

كنت أتوقع هذا:

File oldFile = new File(outputDirectory + fileName + ".temp");
File newFile = new File(outputDirectory + fileName + ".xml");

بشكل عام ، يبدو أن هناك حالة سباق بين كتابة ملف XML ومهمة القراءة/العملية/إعادة تسمية. هل يمكن أن تعمل مهمة القراءة/المعالجة/إعادة تسمية فقط على الملفات> دقيقة واحدة أو شيء مشابه؟

أو ، اطلب من برنامج Java كتابة ملف فارغ إضافي بمجرد إكمال كتابة ملف XML الذي يشير إلى اكتمال الكتابة إلى ملف XML. قراءة/معالجة/إعادة تسمية ملف XML فقط عند وجود ملف الإشارة. ثم احذف ملف الإشارة.

من المؤكد أن الخطأ الأصلي يبدو وكأنه مشكلة مع الوصول المتزامن إلى الملف - يجب أن يكون الحل الخاص بك قد نجح ، ولكن هناك حلول بديلة أيضًا.

على سبيل المثال ، ضع جهاز توقيت على عملية القراءة التلقائية حتى يتم اكتشاف ملف جديد ، فإنه يسجل ملفات الملفات ، وينام X Seconds ، ثم إذا لم تتطابق الأحجام مع إعادة تشغيل المؤقت. يجب أن تتجنب مشاكل نقل الملف الجزئي.

تحرير: أو تحقق من الطوابع الزمنية على النحو المسبق أعلاه للتحقق من ذلك ، ولكن تأكد من أن هذا قديم بما فيه الكفاية لا يهم أي دقة في الطابع الزمني (على سبيل المثال ، 10 ثوانٍ إلى دقيقة واحدة منذ آخر تعديل).

بالتناوب ، جرب هذا:

File f = new File("foo.xml");
FileOutputStream fos = new FileOutputStream(f);
FileChannel fc = fos.getChannel();
FileLock lock = fc.lock();
(DO FILE WRITE)
fis.flush();
lock.release();
fos.close();

يجب أن يستخدم هذا قفل ملفات نظام التشغيل الأصلي لمنع الوصول المتزامن من خلال البرامج الأخرى (مثل Daemon Deemon XML).

فيما يتعلق بمواطن الخلل في NFS: هناك "ميزة" موثقة (خطأ) حيث لا يمكن نقل الملفات بين أنظمة الملفات عبر "إعادة تسمية" في Java. هل يمكن أن يكون هناك ارتباك ، لأنه على نظام ملفات NFS؟

بعض المعلومات إلى NFS بشكل عام. اعتمادًا على إعدادات NFS ، قد لا تعمل الأقفال على الإطلاق ، ويتم ضبط الكثير من منشآت NFS الكبيرة لأداء القراءة ، وبالتالي قد تظهر البيانات الجديدة في وقت لاحق من المتوقع ، بسبب تأثيرات التخزين المؤقت.

لقد رأيت تأثيرات حيث قمت بإنشاء ملف ، وأضاف البيانات (شوهد هذا على جهاز آخر) ، ولكن جميع البيانات بعد ذلك ظهرت مع تأخير 30 ثانية.

أفضل حل بالمناسبة هو مخطط ملف الدوار. بحيث يُفترض أن آخر واحد قد كتب ويتم كتابة واحد من قبل ويمكن قراءته. لن أعمل على ملف واحد وأستخدمه كـ "أنبوب".

يمكنك بدلاً من ذلك استخدام ملف فارغ يتم كتابته بعد كتابة الملف الكبير وإغلاقه بشكل صحيح. لذلك إذا كان هناك الرجال الصغار ، فقد تم بشكل نهائي ، يمكن قراءته.

ربما بسبب "عملية إعادة التسمية قد لا تكون قادرة على نقل ملف من نظام ملفات إلى آخر" http://java.sun.com/j2se/1.5.0/docs/api/java/io/file.html#renameto٪28java.io.file٪2) حاول استخدام Apache Commons io filtutils.copyfiletodirectory http://commons.apache.org/io/api-release/org/apache/commons/io/fileutils.html#copyfiletodirectory(java.io.file ،٪20java.file) في حين أن

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top