Файл, созданный с помощью fmemopen, не имеет содержимого после записи

У меня есть несколько файлов на диске, которые я хочу прочитать и объединить. Я не хочу создавать новый временный файл на диске. Поэтому я решил использовать fmemopen для чтения/записи в память и доступа к ней с помощью API-интерфейсов FILE (я уже написал другой код, который работал только с одним файлом).

Исключая проверку ошибок, по существу у меня есть:

#define MODE_APPEND "a"

int main(int argc, char *argv[]) {    
  off_t concatenated_file_size = 0;
  for (int i = 1; i < argc; i++) {
    concatenated_file_size += get_file_size(argv[i]);
  }

  char *buf = nullptr;
  FILE *concatenated_file = fmemopen(buf, concatenated_file_size, MODE_APPEND);

  for (int i = 1; i < argc; i++) {
    FILE *file_to_concat = open_file(argv[i]);
    int c;
    while ((c = fgetc(file_to_concat)) != EOF) {
      fputc(c, concatenated_file);
    }
  }
  rewind(concatenated_file);
  int prevchar = fgetc(concatenated_file);
}

get_file_size просто использует stat, а open_file — это просто fopen с проверкой ошибок — оба работают корректно, как показало мое тестирование.

Однако prevchar всегда является EOF — почему-то ничего не записывается в FILE*, возвращаемый fmemopen. Вот как должен работать этот API? Я делаю что-то неправильно?

С fmemopen есть странность, я не могу вспомнить подробностей, но мне в голову приходит то, что на самом деле вам нужен open_memstream.

zwol 03.07.2024 05:24

Я посмотрел на это, но согласно stackoverflow.com/a/30642781/6185049 мы не можем использовать API-интерфейсы FILE для чтения из него, и вместо этого нам приходится читать из буфера в памяти.

Nate 03.07.2024 05:59

Что такое MODE_APPEND? И почему вы запутываете строки стандартного режима?

Andrew Henle 03.07.2024 13:23

Извините, у меня просто были константы для них. Это просто «а».

Nate 03.07.2024 17:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете читать из файлового потока, доступного только для записи (добавления). Использование "a" позволяет только добавлять данные, а не читать из потока. Вместо этого используйте "a+" или "w+" — возможно, "w+".

Если вы предоставили буфер (а не нулевой указатель), предположительно, вы можете получить доступ к содержимому напрямую, скопировав его из буфера. Вы можете использовать это, чтобы увидеть, содержит ли буфер то, что вы ожидаете. При автоматически выделяемом буфере (вы указываете нулевой указатель на fmemopen()) такой возможности у вас нет.

... предположительно вам разрешено читать непосредственно из буфера. Не для char *buf = nullptr;: «Если в качестве аргумента buf указан нулевой указатель, fmemopen() должен выделить size байтов памяти, как если бы это был вызов malloc(). Этот буфер должен автоматически освобождаться при закрытии потока. Поскольку эта функция полезна только тогда, когда поток открыт для обновления (поскольку нет возможности получить указатель на буфер), вызов fmemopen() может завершиться неудачей, если аргумент режима не содержит «+».

Andrew Henle 03.07.2024 18:15

@AndrewHenle: Я не особо всматривался в код — проблема "a" vs "a+" была моей главной темой. Я изменил этот абзац. Спасибо!

Jonathan Leffler 03.07.2024 18:50

Я никогда не видел, чтобы fmemopen() использовался с таким указателем NULL - изначально я предполагал, что передача указателя NULL является ошибкой, и на самом деле пошел читать документацию - представьте себе это. IME open_memstream() используется, когда к данным необходимо получить доступ после их записи.

Andrew Henle 03.07.2024 19:42

Другие вопросы по теме