مقدمة
تسلط هذه المقالة الضوء على المهام التي من المرجح أن يواجهها مبرمجو التطبيقات، وخاصة في تطبيقات الويب، مثل:
- قراءة وكتابة ملفات نصية
- قراءة النصوص والصور وJSON من الويب
- زيارة الملفات الموجودة في الدليل
- قراءة ملف ZIP
- إنشاء ملف أو دليل مؤقت
تدعم واجهة برمجة تطبيقات Java العديد من المهام الأخرى، والتي يتم شرحها بالتفصيل في برنامج تعليمي حول واجهة برمجة تطبيقات الإدخال والإخراج في Java.
تسلط هذه المقالة الضوء على تحسينات واجهة برمجة التطبيقات منذ إصدار Java 8. وبشكل خاص:
- UTF-8 هو الإعداد الافتراضي للإدخال والإخراج منذ Java 18 (منذ JEP 400: UTF-8 افتراضيًا)
- ال
java.nio.file.Files
الفئة، التي ظهرت لأول مرة في Java 7، أضافت طرقًا مفيدة في Java 8 و11 و12 java.io.InputStream
اكتسبت طرقًا مفيدة في Java 9 و11 و12- ال
java.io.File
وjava.io.BufferedReader
أصبحت الفصول الدراسية الآن قديمة تمامًا، على الرغم من ظهورها بشكل متكرر في عمليات البحث على الويب ومحادثات الذكاء الاصطناعي.
قراءة ملفات النصوص
يمكنك قراءة ملف نصي إلى سلسلة مثل هذا:
String content=Files.readString(path);
هنا، path
هو مثال على java.nio.Path
، تم الحصول عليها على هذا النحو:
var path=Path.of("/usr/share/dict/words");
قبل Java 18، كان من المستحسن بشدة تحديد ترميز الأحرف مع أي عمليات ملفات تقرأ أو تكتب سلاسل. في الوقت الحاضر، يعد ترميز الأحرف الأكثر شيوعًا هو UTF-8، ولكن من أجل التوافق مع الإصدارات السابقة، استخدمت Java “ترميز النظام الأساسي”، والذي يمكن أن يكون ترميزًا قديمًا على Windows. لضمان قابلية النقل، كانت عمليات إدخال/إخراج النص بحاجة إلى معلمات StandardCharsets.UTF_8
. هذا لم يعد ضروريا.
إذا كنت تريد الملف كسلسلة من الأسطر، فاتصل بـ
List lines=Files.readAllLines(path);
إذا كان الملف كبيرًا، قم بمعالجة الأسطر ببطء كـ Stream
:
try (Stream lines=Files.lines(path)) { . . .}
أيضا استخدام Files.lines
إذا كان بإمكانك معالجة الخطوط بشكل طبيعي باستخدام عمليات التدفق (مثل map
, filter
). لاحظ أن الدفق الذي تم إرجاعه بواسطة Files.lines
يجب إغلاقه. للتأكد من حدوث ذلك، استخدم حاول استخدام الموارد العبارة، كما هو الحال في مقتطف التعليمات البرمجية السابق.
لم يعد هناك سبب وجيه لاستخدام readLine
طريقة java.io.BufferedReader
.
لتقسيم مدخلاتك إلى شيء آخر غير الأسطر، استخدم java.util.Scanner
على سبيل المثال، إليك كيفية قراءة الكلمات، مفصولة بأحرف غير مترابطة:
Stream tokens=new Scanner(path).useDelimiter("\PL+").tokens();
ال Scanner
تحتوي الفئة أيضًا على طرق لقراءة الأرقام، ولكن من الأسهل عمومًا قراءة المدخلات كسلسلة واحدة لكل سطر، أو سلسلة واحدة، ثم تحليلها.
كن حذرًا عند تحليل الأرقام من ملفات نصية، حيث قد يعتمد تنسيقها على الموقع المحلي. على سبيل المثال، قد يكون ملف الإدخال 100.000
100.0 في الإعدادات المحلية للولايات المتحدة ولكن 100000.0 في الإعدادات المحلية الألمانية. استخدم java.text.NumberFormat
للتحليل المحلي المحدد. بدلاً من ذلك، قد تتمكن من استخدام Integer.parseInt
/Double.parseDouble
.
كتابة ملفات نصية
يمكنك كتابة سلسلة إلى ملف نصي بمكالمة واحدة:
String content=. . .;Files.writeString(path, content);
إذا كان لديك قائمة من الأسطر بدلاً من سلسلة واحدة، استخدم:
List lines=. . .;Files.write(path, lines);
للحصول على نتائج أكثر عمومية، استخدم PrintWriter
إذا كنت تريد استخدام printf
طريقة:
var writer=new PrintWriter(path.toFile());writer.printf(locale, "Hello, %s, next year you'll be %d years old!%n", name, age + 1);
لاحظ أن printf
يعتمد على الموقع. عند كتابة الأرقام، تأكد من كتابتها بالتنسيق المناسب. بدلاً من استخدام printf
، يعتبر java.text.NumberFormat
أو Integer.toString
/Double.toString
.
من الغريب أنه اعتبارًا من Java 21، لا يوجد PrintWriter
منشئ مع Path
معامل.
إذا لم تستخدم printf
، يمكنك استخدام ال BufferedWriter
الصف وكتابة السلاسل باستخدام write
طريقة.
var writer=Files.newBufferedWriter(path);writer.write(line); // Does not write a line separatorwriter.newLine();
تذكر أن تغلق writer
عندما تنجز.
القراءة من مجرى الإدخال
ربما يكون السبب الأكثر شيوعًا لاستخدام الدفق هو قراءة شيء ما من موقع ويب.
إذا كنت بحاجة إلى تعيين رؤوس الطلب أو قراءة رؤوس الاستجابة، فاستخدم HttpClient
:
HttpClient client=HttpClient.newBuilder().build();HttpRequest request=HttpRequest.newBuilder() .uri(URI.create("https://horstmann.com/index.html")) .GET() .build();HttpResponse response=client.send(request, HttpResponse.BodyHandlers.ofString());String result=response.body();
هذا أمر مبالغ فيه إذا كان كل ما تريده هو البيانات. بدلاً من ذلك، استخدم:
InputStream in=new URI("https://horstmann.com/index.html").toURL().openStream();
ثم اقرأ البيانات في مصفوفة بايتات وقم بتحويلها اختياريًا إلى سلسلة:
byte[] bytes=in.readAllBytes();String result=new String(bytes);
أو نقل البيانات إلى مجرى الإخراج:
OutputStream out=Files.newOutputStream(path);in.transferTo(out);
لاحظ أنه لا يلزم وجود حلقة إذا كنت تريد ببساطة قراءة كافة بايتات مجرى الإدخال.
ولكن هل تحتاج حقًا إلى تدفق إدخال؟ تتيح لك العديد من واجهات برمجة التطبيقات خيار القراءة من ملف أو عنوان URL.
من المرجح أن تحتوي مكتبة JSON المفضلة لديك على طرق للقراءة من ملف أو عنوان URL. على سبيل المثال، مع جاكسون جونيور:
URL url=new URI("https://dog.ceo/api/breeds/image/random").toURL();Map result=JSON.std.mapFrom(url);
إليك كيفية قراءة صورة الكلب من المكالمة السابقة:
URL url=new URI(result.get("message").toString()).toURL();BufferedImage img=javax.imageio.ImageIO.read(url);
هذا أفضل من تمرير دفق الإدخال إلى read
الطريقة، لأن المكتبة يمكنها استخدام معلومات إضافية من عنوان URL لتحديد نوع الصورة.
واجهة برمجة التطبيقات للملفات
ال java.nio.file.Files
توفر الفئة مجموعة شاملة من عمليات الملفات، مثل إنشاء الملفات والدلائل ونسخها ونقلها وحذفها. أساسيات نظام الملفات يوفر البرنامج التعليمي وصفًا شاملاً. في هذا القسم، أسلط الضوء على بعض المهام الشائعة.
التنقل بين الإدخالات في الدلائل والدلائل الفرعية
في معظم المواقف، يمكنك استخدام إحدى الطريقتين. Files.list
تقوم الطريقة بزيارة جميع الإدخالات (الملفات، الدلائل الفرعية، الروابط الرمزية) الخاصة بالدليل.
try (Stream entries=Files.list(pathToDirectory)) { . . .}
إستخدم حاول استخدام الموارد عبارة للتأكد من أن كائن التدفق، الذي يتتبع التكرار، سيتم إغلاقه.
إذا كنت تريد أيضًا زيارة إدخالات الدلائل الفرعية، فاستخدم بدلاً من ذلك الطريقة Files.walk
Stream entries=Files.walk(pathToDirectory);
ثم استخدم ببساطة طرق التدفق للتركيز على الإدخالات التي تهمك، وجمع النتائج:
try (Stream entries=Files.walk(pathToDirectory)) { List htmlFiles=entries.filter(p -> p.toString().endsWith("html")).toList(); . . .}
وفيما يلي الطرق الأخرى لاجتياز إدخالات الدليل:
- نسخة محملة من
Files.walk
يتيح لك تحديد عمق الشجرة التي تم عبورها. - اثنين
Files.walkFileTree
توفر الأساليب مزيدًا من التحكم في عملية التكرار، من خلال إخطارFileVisitor
عند زيارة دليل للمرة الأولى والأخيرة. قد يكون هذا مفيدًا في بعض الأحيان، وخاصةً لتفريغ وحذف شجرة من الدلائل. راجع البرنامج التعليمي المشي على شجرة الملف للحصول على التفاصيل. ما لم تكن بحاجة إلى هذا التحكم، استخدم أبسطFiles.walk
طريقة. - ال
Files.find
الطريقة هي تماما مثلFiles.walk
ولكنك توفر مرشحًا يفحص كل مسار ومساره.BasicFileAttributes
يعد هذا أكثر كفاءة إلى حد ما من قراءة السمات بشكل منفصل لكل ملف. - اثنين
Files.newDirectoryStream(Path)
الأساليب تنتجDirectoryStream
الحالات التي يمكن استخدامها في تحسينfor
الحلقات. لا توجد ميزة في استخدامFiles.list
. - الإرث
File.list
أوFile.listFiles
الأساليب ترجع أسماء الملفات أوFile
الأشياء. هذه الأشياء أصبحت قديمة الآن.
العمل مع ملفات ZIP
منذ إصدار Java 1.1، ZipInputStream
و ZipOutputStream
توفر الفئات واجهة برمجة تطبيقات لمعالجة ملفات ZIP. لكن واجهة برمجة التطبيقات غير سلسة بعض الشيء. قدمت Java 8 واجهة برمجة تطبيقات أفضل كثيرًا نظام الملفات ZIP:
try (FileSystem fs=FileSystems.newFileSystem(pathToZipFile)) { . . .}
ال حاول استخدام الموارد يضمن البيان أن close
يتم استدعاء الطريقة بعد عمليات ملف ZIP. تقوم هذه الطريقة بتحديث ملف ZIP ليعكس أي تغييرات في نظام الملفات.
يمكنك بعد ذلك استخدام أساليب Files
الصف. هنا نحصل على قائمة بجميع الملفات الموجودة في ملف ZIP:
try (Stream entries=Files.walk(fs.getPath("/"))) { List filesInZip=entries.filter(Files::isRegularFile).toList();}
لقراءة محتويات الملف، استخدم فقط Files.readString
أو Files.readAllBytes
:
String contents=Files.readString(fs.getPath("/LICENSE"));
يمكنك إزالة الملفات باستخدام Files.delete
لإضافة أو استبدال الملفات، استخدم ببساطة Files.writeString
أو Files.write
.
إنشاء الملفات والدلائل المؤقتة
في كثير من الأحيان، أحتاج إلى جمع مدخلات المستخدم وإنتاج ملفات وتشغيل عملية خارجية. ثم أستخدم ملفات مؤقتة، والتي تختفي بعد إعادة التشغيل التالية، أو دليل مؤقت أقوم بمسحه بعد اكتمال العملية.
أستخدم الطريقتين Files.createTempFile
و Files.createTempDirectory
من أجل هذا.
Path filePath=Files.createTempFile("myapp", ".txt");Path dirPath=Files.createTempDirectory("myapp");
يؤدي هذا إلى إنشاء ملف أو دليل مؤقت في موقع مناسب (/tmp
في Linux) بالبادئة المحددة، وبالنسبة للملف، اللاحقة.
خاتمة
قد تقترح عمليات البحث على الويب والمحادثات عبر الذكاء الاصطناعي أكوادًا معقدة لا داعي لها لعمليات الإدخال/الإخراج الشائعة. غالبًا ما توجد بدائل أفضل:
- لا تحتاج إلى حلقة لقراءة أو كتابة السلاسل أو مصفوفات البايتات.
- ربما لا تحتاج حتى إلى دفق أو قارئ أو كاتب.
- تعرف على
Files
طرق إنشاء الملفات والدلائل ونسخها ونقلها وحذفها. - يستخدم
Files.list
أوFiles.walk
للتنقل بين إدخالات الدليل. - استخدم نظام ملفات ZIP لمعالجة ملفات ZIP.
- ابتعد عن الإرث
File
فصل.