встраивание текстового файла в exe-файл, доступ к которому можно получить с помощью fopen - PullRequest
2 голосов
/ 09 сентября 2011

Я хотел бы добавить текстовый файл с некоторыми данными в мою программу. давайте назовем это « data.txt ».

Этот текстовый файл обычно загружается с функцией, которая требует ввода имени файла текстового файла и в конечном итоге открывается с помощью вызова fopen () ... что-то в строках

FILE* name = fopen("data.txt");

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

Итак, мой вопрос: есть ли способ встроить текстовый файл как вызываемый файл / переменную в fopen ()?

Я использую VS2008.

Ответы [ 3 ]

2 голосов
/ 09 сентября 2011

Да и нет. Самый простой способ - преобразовать содержимое текстового файла в инициализированный массив.

char data_txt[] = {
    'd','a','t','a',' ','g','o','e','s',' ','h','e','r','e', //....
};

Это преобразование легко выполнить с помощью небольшого Perl-скрипта или даже небольшой C-программы.Затем вы компилируете и связываете полученный модуль с вашей программой.

Старая хитрость, облегчающая управление с помощью Makefile, заключается в том, чтобы скрипт преобразовывал свои данные в тело инициализатора.и записать его в файл без объявления окружающих переменных или даже фигурных скобок.Если data.txt преобразуется в data.inc, то он используется следующим образом:

char data_txt[] = {
#include "data.inc"
};

Обновление

На многих платформах можно добавлять произвольныеданные в сам исполняемый файл.Хитрость заключается в том, чтобы найти его во время выполнения.На платформах, где это возможно, будет информация заголовка файла для исполняемого файла, которая указывает длину исполняемого образа.Это можно использовать для вычисления смещения для использования с fseek() после того, как вы открыли исполняемый файл для чтения.Это труднее сделать переносным способом, поскольку может даже оказаться невозможным узнать фактическое имя файла вашего исполняемого образа во время выполнения переносимым способом.(Подсказка, argv[0] необязательно указывать на реальную программу.)

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

Если вы можете отбросить вызов до fopen(), но при этом все еще нужно FILE *, указывая на данные, тогда это, вероятно,возможно , если , вы готовы играть быстро и свободно с реализацией вашей библиотеки времени выполнения C на stdio.В GNU-версии libc такие функции, как sprintf() и sscanf(), на самом деле реализованы путем создания "достаточно реального" FILE *, который можно передать в общую реализацию (vfprintf() и vfscanf(), IIRC).Этот фальшивый FILE помечается как буферизованный и указывает его буфер на буфер пользователя.Некоторая магия используется, чтобы убедиться, что остальная часть stdio не делает глупостей.

1 голос
/ 03 марта 2014

Для любого типа файла , на основе RBerteig anwser вы можете сделать что-то простое с python:

Эта программа создаст файл text.txt.c, который можно скомпилироватьи связаны с вашим кодом, чтобы встроить любой текстовый или двоичный файл непосредственно в ваш exe-файл и прочитать его непосредственно из переменной:

import struct;                  #    Needed to convert string to byte

f = open("text.txt","rb")       #    Open the file in read binary mode
s = "unsigned char text_txt_data[] = {"

b = f.read(1)                   #    Read one byte from the stream
db = struct.unpack("b",b)[0]     #    Transform it to byte
h = hex(db)                      #    Generate hexadecimal string
s = s + h;                      #    Add it to the final code
b = f.read(1)                   #    Read one byte from the stream

while b != "":
    s = s + ","                 #    Add a coma to separate the array
    db = struct.unpack("b",b)[0] #    Transform it to byte
    h = hex(db)                  #    Generate hexadecimal string
    s = s + h;                  #    Add it to the final code
    b = f.read(1)               #    Read one byte from the stream

s = s + "};"                     #    Close the bracktes
f.close()                       #    Close the file

# Write the resultan code to a file that can be compiled
fw = open("text.txt.c","w");   
fw.write(s);
fw.close();

Будет сгенерировано что-то вроде

unsigned char text_txt_data[] = {0x52,0x61,0x6e,0x64,0x6f,0x6d,0x20,0x6e,0x75...

Вы можете последнимиспользуйте ваши данные в другом файле c, используя переменную с кодом, подобным следующему:

extern unsigned char text_txt_data [];

Прямо сейчас я не могу придумать два способа преобразования его в читаемый текст.Использование потоков памяти или преобразование ее в c-строку.

0 голосов
/ 09 сентября 2011

Нет, такой возможности нет. И именно поэтому C ++ имеет собственный способ чтения файлов: std::ifsteam. Если ваш код будет использовать его, вы можете легко изменить его на std::istringstream для чтения данных из строки памяти вместо файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...