Сделать файловый указатель считываемым/записываемым в ячейку памяти
Я могу сделать запись указателя файла в файл с помощью 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!
EDIT: для тех, кто читает этот вопрос годы спустя, в дополнение к принятому ответу, вы должны посмотреть на open_memstream(3)
, который ведет себя более похоже на эти классы Java, чем fmemopen
.
4 ответа:
Если ваша операционная система предоставляет fmemopen , возможно, это будет соответствовать вашей цели.
В C++ (и вы добавили тег C++) можно написать функцию, принимающую произвольный поток ввода / вывода. Так как
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 } }
Как метко указывает 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*, то C++ удобно предоставляетstd::istringstream
иstd::ostringstream
для чтения/записи строк.Вы заметите, что почти все функции в C, которые начинаются с "f "и которые работают с файлами, имеют эквиваленты, начинающиеся с" s", которые работают со строками. Возможно, лучшим подходом было бы разработать интерфейс для ввода-вывода, который не является специфичным для либо файлы, либо строки, а затем предоставить реализации, которые подключаются к файлам и строкам соответственно. Затем реализуйте свою основную логику в терминах этого интерфейса, а не в терминах низкоуровневого ввода-вывода C и C++, что также дает возможность для будущих расширений, таких как поддержка сетевых файлов со встроенной поддержкой сжатия, дублирования и т. д.
С файлом, сопоставленным с памятью. Это относится к конкретной платформе, поэтому вам нужно будет найти информацию о создании mem-сопоставленных файлов в вашей целевой системе(системах). Я считаю, что версия posix - это
mmap
. В любом случае, поиск "файла с отображением памяти" в google должен найти кучу справок.