هل يمكن استخدام إجراءات الإخراج التي تطبع إلى ملف* لإنشاء سلسلة في لغة C؟

StackOverflow https://stackoverflow.com/questions/1270212

  •  13-09-2019
  •  | 
  •  

سؤال

لدي شعور سيء بأن الإجابة على هذا السؤال هي "لا"، لكنني أردت أن أطرح هذا في حال كان لدى أي شخص أي أفكار ذكية.

لدي مجموعة من إجراءات الإخراج التي تأخذ بنية بيانات معقدة وتطبعها بتنسيق نصي.لديهم نماذج أولية مثل:

void print_mystruct(struct mystruct *s, FILE *stream)

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

لسوء الحظ، لا توجد طريقة أعرفها، باستخدام المعيار C99، يمكنني من خلالها استخدام نفس هذه الإجراءات لإنشاء سلسلة في الذاكرة.

لذلك أسئلتي هي:

  1. هل هناك أي طريقة ذكية يمكنني من خلالها استخدام fputs() و fprintf() بكفاءة وما إلى ذلك.لإخراج إلى سلسلة؟
  2. إذا لم يكن الأمر كذلك، فهل هناك نموذج أفضل يمكنه القيام بكفاءة بإخراج الملفات المخزنة مؤقتًا وبناء السلسلة؟أفضل ما يمكنني التفكير فيه هو أن يكون لدي هيكل خاص بي باستخدام vtable (بدلاً من FILE*).سيكون لدى vtable وظيفة إخراج من شأنها إما إلحاق سلسلة أو استدعاء fwrite.ولكن بعد ذلك سيتعين علي إنشاء أغلفة printf أيضًا.

أي أفكار ذكية أخرى؟

يحرر:لقد اكتشفت ذلك fmemopen() هو جزء من POSIX.1-2008 (انظر: فميموبين ()) ولكنه غير مدعوم على نطاق واسع، على الأقل وفقًا لصفحة GNU libc.

هل كانت مفيدة؟

المحلول

لا توجد طريقة محمولة للقيام بذلك.أنظمة glibc (لينكس) لديها open_memstream/fmemopen ، قد لا تحتوي الأنظمة الأخرى على شيء مثل ذلك.

الطريقة المحمولة هي الكتابة إلى ملف وقراءته مرة أخرى في سلسلة.أو لفصل المخاوف.بدلا من التنفيذ

void print_mystruct(struct mystruct *s,FILE *f);

كنت على سبيل المثال.ينفذ

char *mystruct_2_str(struct mystruct *s);

الذي يخصص سلسلة ديناميكيًا (أو يمررها في مخزن مؤقت)، وينسقها إلى سلسلة ذات وظائف سلسلة قياسية (snprintf وما إلى ذلك) ويطلب من المتصل أن يقرر ما إذا كان سيكتب ذلك إلى ملف*

نصائح أخرى

إذا كنت لا تهتم بالبحث عن الملف، فهناك طريقة محمولة (لجميع أهداف POSIX السابقة) للحصول على نفس التأثير مثل fmemopen, ، لكنها مكلفة إلى حد ما.اصنع أنبوبًا وخيطًا منفصلاً جديدًا و fdopen نهاية الكتابة للأنبوب في خيط الاستدعاء.يقرأ الخيط الجديد بعد ذلك من نهاية القراءة للأنبوب ويضع البيانات في المخزن المؤقت للسلسلة.اجعل الخيط الجديد يعود عندما يحصل على EOF من الأنبوب؛نظرًا لأنه منفصل، فلا يوجد أي تنظيف للقيام به.

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

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;

يمكنك تصنيع إحدى هذه البنيات بنفسك من مخزن مؤقت للسلسلة وتمريرها إلى وظيفتك، وكذلك إنشاء وظيفة تفكيك تحرر الذاكرة.

السؤال هو، ما هي مكالمات مكتبة CRT التي يمكنك استخدامها في الإصدار الخاص بك؟من الواضح أن أي شيء يشير إلى اسم الملف سوف يفشل، نظرًا لعدم وجود اسم الملف.ولكن ربما يمكنك استخدام وظائف مثل fwrite وfread وfseek، والتي ستتعامل مع المؤشرات وتخصيص مساحة أكبر إذا لزم الأمر.

#include <stdio.h>
#include <stdlib.h>

char* file_to_string(FILE *f, int *len) {
  if (fseek(f, 0, SEEK_END)) handle_error();
  int buflen = ftell(f);
  if (len) *len = buflen;
  char *buf = malloc(buflen + 1);
  buf[buflen] = '\0';
  rewind(f);
  size_t readlen = fread(buf, 1, buflen, f);
  if (readlen != buflen) handle_error();
  // in particular, note readlen might not equal buflen in the face of text-mode
  // conversions, but tmpfile() indicates binary-mode, so doesn't affect this
  // case
  return buf;
}

int main() {
  FILE *temp = tmpfile();

  // use FILE interface
  fputs("written to temporary file\n", temp);

  char *s = file_to_string(temp, NULL);
  // now you have contents as a string
  free(s);

  // can also rewind the FILE and process it incrementally, etc.

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