استخدام مكالمات النظام لتنفيذ أمر UNIX CAT
-
28-09-2019 - |
سؤال
بالنسبة لفصل نظام التشغيل الخاص بي ، لديّ مهمة لتنفيذ أمر CAT الخاص بـ UNIX مع مكالمات النظام (بدون SCANF أو PRINTF). هذا ما حصلت عليه حتى الآن:
(تم تحريره بفضل الردود)
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
main(void)
{
int fd1;
int fd2;
char *buffer1;
buffer1 = (char *) calloc(100, sizeof(char));
char *buffer2;
buffer2 = (char *)calloc(100, sizeof(char));
fd1 = open("input.in", O_RDONLY);
fd2 = open("input2.in", O_RDONLY);
while(eof1){ //<-lseek condition to add here
read (fd1, buffer1, /*how much to read here?*/ );
write(1, buffer1, sizeof(buffer1)-1);
}
while (eof2){
read (fd2,buffer2, /*how much to read here?*/);
write(1, buffer2, sizeof(buffer2)-1);
}
}
الأمثلة التي رأيتها تظهر فقط مع عدد معروف من البايتات. لا أعرف كم سيحصل كل من ملفات القراءة ، فكيف يمكنني تحديد بارامثر للقراءة؟
المحلول
- قبل أن تستطيع
read
في المخزن المؤقت ، عليك تخصيص واحدة. إما على المكدس (الأسهل) أو معmmap
. perror
هي وظيفة مكتبة معقدة ، وليس مكالمة النظام.exit
ليست دعوة نظام على Linux. ولكن_exit
هو.- لا
write
بايت أكثر مما لديكread
قبل. - أو بشكل عام: اقرأ الوثائق حول جميع مكالمات النظام هذه.
يحرر: هنا هو الكود الخاص بي ، باستخدام مكالمات النظام فقط. معالجة الأخطاء محدودة إلى حد ما ، لأنني لم أرغب في إعادة التنفيذ perror
.
#include <fcntl.h>
#include <unistd.h>
static int
cat_fd(int fd) {
char buf[4096];
ssize_t nread;
while ((nread = read(fd, buf, sizeof buf)) > 0) {
ssize_t ntotalwritten = 0;
while (ntotalwritten < nread) {
ssize_t nwritten = write(STDOUT_FILENO, buf + ntotalwritten, nread - ntotalwritten);
if (nwritten < 1)
return -1;
ntotalwritten += nwritten;
}
}
return nread == 0 ? 0 : -1;
}
static int
cat(const char *fname) {
int fd, success;
if ((fd = open(fname, O_RDONLY)) == -1)
return -1;
success = cat_fd(fd);
if (close(fd) != 0)
return -1;
return success;
}
int
main(int argc, char **argv) {
int i;
if (argc == 1) {
if (cat_fd(STDIN_FILENO) != 0)
goto error;
} else {
for (i = 1; i < argc; i++) {
if (cat(argv[i]) != 0)
goto error;
}
}
return 0;
error:
write(STDOUT_FILENO, "error\n", 6);
return 1;
}
نصائح أخرى
تحتاج إلى قراءة أكبر عدد من البايتات كما سوف تناسب المخزن المؤقت. في الوقت الحالي ، ليس لديك مخزن مؤقت حتى الآن ، كل ما حصلت عليه هو مؤشر للمخزن المؤقت. لم يتم تهيئتها إلى أي شيء. الدجاج والبلدان ، لذلك أنت لا تعرف عدد البايتات التي يجب قراءتها أيضًا.
إنشاء مخزن مؤقت.
عادة لا توجد حاجة لقراءة الملف بأكمله في بلع واحد. يعد اختيار حجم مخزن مؤقت هو نفسه أو مضاعف حجم صفحة ذاكرة نظام التشغيل المضيف وسيلة جيدة للذهاب. 1 أو 2 × ربما يكون حجم الصفحة جيدًا بما فيه الكفاية.
يمكن أن يؤدي استخدام المخازن المؤقتة التي تكون كبيرة جدًا في الواقع إلى تشغيل البرنامج بشكل أسوأ لأنه يضع ضغطًا على نظام الذاكرة الافتراضية ويمكن أن يسبب الترحيل.
يمكنك استخدام open
, fstat
, mmap
, madvise
و write
لصنع جداً أمر القط الفعال.
إذا كان Linux محددًا يمكنك استخدامه open
, fstat
, fadvise
و splice
لجعل الأمر القط أكثر كفاءة.
تتمثل المكالمات المشورة في تحديد الأعلام المتسلسلة التي ستخبر kernel بالقيام بقراءة القراءة العدوانية على الملف.
إذا كنت ترغب في أن تكون مهذبًا لبقية النظام وتقليل استخدام ذاكرة التخزين المؤقت المخزن المؤقت ، فيمكنك القيام بنسخك في أجزاء من 32 ميغابايت أو نحو ذلك واستخدام نصيحة أعلام Dontneed على الأجزاء التي تقرأها بالفعل.
ملحوظة:
ستعمل ما ورد أعلاه فقط إذا كان المصدر ملفًا. إذا فشلت FSTAT في توفير حجم ، فيجب أن تعود إلى استخدام مخزن مؤقت مخصص و read
, write
. يمكنك استخدام splice
جدا.
استخدم ال Stat وظيفة للعثور على حجم ملفاتك قبل قراءتها. بدلاً من ذلك ، يمكنك قراءة القطع حتى تحصل على EOF.