سؤال

بالنسبة لفصل نظام التشغيل الخاص بي ، لديّ مهمة لتنفيذ أمر 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.

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