Подтвердить что ты не робот

Сделать указатель файла на чтение/запись в ячейку памяти

Я могу записать указатель файла в файл с помощью функции fopen(). Но могу ли я сделать указатель на файл, который сделает так, чтобы вызывающие функции, такие как fputc или fprintf, записывали указатель в память? Примером этого является ByteArrayOutputStream в java. Также: могу ли я запустить его в обратном порядке, где библиотеке нужен указатель на файл для чтения, поэтому я выделяю память и создаю новый указатель на файл, который будет считываться из этой ячейки памяти, но возвращать EOF, когда заканчивается размер куска? (например, ByteArrayInputStream в Java). Есть ли способ сделать это в C? Например:

FILE *p = new_memory_file_pointer();
fprintf(p, "Hello World!\n");
char *data = get_written_stuff(p);
printf("%s", data); //will print Hello World!

& &/||

char s[] = "Hello World!\n";
FILE *p = new_memory_file_pointer_read(s, sizeof(s));
char *buffer = (char *)malloc( 1024*sizeof(char) );
fread((void *)buffer, 1, sizeof(s), p);
printf("%s", buffer); //prints Hello World!

РЕДАКТИРОВАТЬ: Тем, кто читает этот вопрос спустя годы, помимо принятого ответа, вы должны посмотреть open_memstream(3), который ведет себя скорее как эти классы Java, чем fmemopen.

4b9b3361

Ответ 1

Если ваша операционная система предоставляет fmemopen, вероятно, это будет соответствовать вашей цели.

Ответ 2

В С++ (и вы добавили тег С++) вы можете написать функцию, принимающую произвольный поток ввода/вывода. Поскольку std::stringstream или std::ofstream являются производными классами, вы можете передать их одинаково в эту функцию. Пример:

#include <iostream> // for std::cout
#include <fstream> // for std::ofstream
#include <sstream> // for std::stringstream

void write_something(std::ostream& stream) {
  stream << "Hello World!" << std::endl;
}

int main() {
  write_something(std::cout); // write it to the screen
  {
    std::ofstream file("myfile.txt");
    write_something(file); // write it into myfile.txt
  }
  {
    std::stringstream stream;
    write_something(stream); // write it into a string
    std::cout << stream.str() << std::endl; // and how to get its content
  }
}

И аналогично std::istream вместо std::ostream, если вы хотите прочитать данные:

void read_into_buffer(std::istream& stream, char* buffer, int length) {
  stream.read(buffer, length);
}

int main() {
  char* buffer = new char[255];

  {
    std::ifstream file("myfile.txt");
    read_into_buffer(file, buffer, 10); // reads 10 bytes from the file
  }
  {
    std::string s("Some very long and useless message and ...");
    std::stringstream stream(s);
    read_into_buffer(stream, buffer, 10); // reads 10 bytes from the string
  }
}

Ответ 3

Как указывает Ise, существует функция для fmemopen в POSIX 2008 и поддерживается в Linux. Используя POSIX 2004, вероятно, самое близкое к этому было бы использование временного файла:

// This is for illustration purposes only. You should add error checking to this.
char name[] = "/tmp/name-of-app-XXXXXX";
int temporary_descriptor = mkstemp(name);
unlink(temporary_descriptor);
FILE* file_pointer = fdopen(temporary_descriptor, "r+");
// use file_pointer ...

Это проще сделать наоборот; то есть иметь функцию, которая записывает в память, а затем использовать ее как для записи в память, так и для записи в файл. Вы можете использовать mmap, чтобы фрагмент памяти был подкреплен файлом, и запись в эту память записывает данные в соответствующие файл.

Если вы используете std::istream и std::ostream вместо низкоуровневых C FILE * объектов, тогда С++ удобно предоставляет std::istringstream и std::ostringstream для чтения/записи строк.

Вы заметите, что почти все функции в C, которые начинаются с "f" и которые работают с файлами, имеют эквиваленты, начинающиеся с "s", которые работают с строками. Возможно, лучший подход заключался бы в разработке интерфейса для ввода-вывода, который не является специфическим ни для файлов, ни для строк, а затем предоставляет реализации, которые подключаются к файлам и строкам, соответственно. Затем реализуйте свою основную логику в терминах этого интерфейса, а не в терминах ввода-вывода C и С++ низкого уровня. Это также имеет преимущество для будущих расширений, таких как поддержка сетевых файлов со встроенной поддержкой сжатия, дублирования и т.д.

Ответ 4

С файлом с отображением памяти. Это зависит от платформы, поэтому вам нужно будет найти информацию о создании mem-mapped файлов в вашей целевой системе. Я считаю, что версия posix mmap. Во всяком случае, поиск "файла с отображением памяти" в google должен появиться с помощью справки.