Получить строку файла во время компиляции [дубликат]

Я просто хотел добавить еще одно предостережение, которое я нашел в своем тестировании:

при использовании select load_file('/path/to/theFile.txt'); Загружаемый файл HAS должен быть на компьютере, в котором работает экземпляр sql.

Это бит меня в прикладе в течение долгого времени, потому что я использую MySQL workbench для загрузки файлов все время в наши различные экземпляры sql, и при использовании таких команд, как LOAD DATA LOCAL INFILE 'C:/path/to/theFile.csv' INTO TABLE, они легко хватают файл из моего локального жесткий диск и обрабатывать его в таблицах независимо от того, где был запущен фактический экземпляр sql. Однако команда load_file, по-видимому, не ведет себя как минимум для меня одинаково (возможно, существует команда local_load_file (), о которой я не знаю). MySQL, похоже, только позволяет искать файлы из локальной системы, в которой запущен экземпляр sql.

Итак, если вы похожи на меня, и вы не можете понять, почему load_file всегда возвращает NULL, нет страх ... загружайте файлы в экземпляр сервера sql, а затем используйте этот путь из браузера Query, и все будет хорошо.

101
задан Brian Tompsett - 汤莱恩 15 February 2016 в 22:37
поделиться

15 ответов

Я бы предложил использовать (unix util) xxd для этого. вы можете использовать его так:

$ echo hello world > a
$ xxd -i a

выходы:

unsigned char a[] = {
  0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x0a
};
unsigned int a_len = 12;
105
ответ дан Hasturkun 15 August 2018 в 23:04
поделиться
  • 1
    Просто примечание: char [], созданный xxd, не завершен NULL! поэтому я делаю $ xxd -i & lt; file.txt & gt; file.xxd $ echo ', 0' & gt; gt; file.xxd и в main.c char file_content [] = {#include & quot; file.xxd & quot; }; – user 4 January 2009 в 17:10
  • 2
    Я никогда не знал о xxd. Это здорово! – user 6 January 2009 в 01:29
  • 3
    @Hasturkun: Я понимаю, как вы создали результат с помощью xxd. Я не понимаю, как вы собираетесь включить xxd в свой C-код. В конце концов xxd является командой оболочки. Как вы собираетесь использовать его из C-программы? – Lazer 20 March 2010 в 12:33
  • 4
    @eSKay: это происходит непосредственно из вывода xxd, как говорит ответ. имя массива - имя входного файла. если вы используете данные для передачи данных вместо использования входного файла, вместо этого вы получите список шестнадцатеричных значений (без объявления массива или переменной len). – Hasturkun 22 March 2010 в 00:42
  • 5
    Еще один способ добавления 0x00 завершения к xxd создал C-код: xxd -i file.txt | sed 's/\([0-9a-f]\)$/\0, 0x00/' > file.h – vleo 26 February 2016 в 18:36

Вопрос был о C, но если кто-то попытается сделать это с C ++ 11, то это может быть сделано с небольшими изменениями в включенном текстовом файле благодаря новым строковым литералам :

В C ++ сделайте следующее:

const char *s =
#include "test.txt"
;

В текстовом файле сделайте следующее:

R"(Line 1
Line 2
Line 3
Line 4
Line 5
Line 6)"

Поэтому должен быть только префикс в верхней части файл и суффикс в конце его. Между ними вы можете делать то, что хотите, не требуется специального экранирования, если вам не нужна последовательность символов )". Но даже это может работать, если вы укажете свой собственный разделитель:

R"=====(Line 1
Line 2
Line 3
Now you can use "( and )" in the text file, too.
Line 5
Line 6)====="
77
ответ дан Christophe 15 August 2018 в 23:04
поделиться
  • 1
    Спасибо, я выбрал предложенный здесь метод для вставки длинных фрагментов sql в мой код C ++ 11. Это позволяет мне легко разделить SQL на свои собственные файлы и редактировать их с помощью соответствующей проверки синтаксиса, выделения и т. Д. – YitzikC 29 January 2017 в 22:58
  • 2

ok, вдохновленный сообщением Daemin's , я проверил следующий простой пример:

a.data:

"this is test\n file\n"

test.c:

int main(void)
{
    char *test = 
#include "a.data"
    ;
    return 0;
}

gcc -E test.c output:

# 1 "test.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "test.c"

int main(void)
{
    char *test =
# 1 "a.data" 1
"this is test\n file\n"
# 6 "test.c" 2
    ;
    return 0;
}

Итак, он работает, но требует данных, окруженных кавычками.

14
ответ дан Community 15 August 2018 в 23:04
поделиться
  • 1
    последняя строка должна, вероятно, читать «cat file.bin | ./bin2c & gt; data.h & Quot; или "./ bin2c & lt; file.bin & gt; data.h & Quot; – Hasturkun 4 January 2009 в 15:08
  • 2
    Это то, о чем я упоминал в последнем ответе. – Daemin 4 January 2009 в 23:11
  • 3
    Полный кредит предоставляется :) – Ilya 5 January 2009 в 06:23
  • 4
    Данные, окруженные запятыми ? – bdonlan 28 July 2009 в 18:28
  • 5
    цитата или что бы то ни было, прошу прощения за мой английский – Ilya 29 July 2009 в 16:32
  • 6
    Я использовал codeproject.com/Tips/845393/… , чтобы создать шестнадцатеричный файл (в Windows) из двоичного файла, а затем использовал ваше предложение char my_file[] = { #include my_large_file.h }; Спасибо! – Someone Somewhere 5 January 2016 в 13:10

Что может работать, если вы делаете что-то вроде:

int main()
{
    const char* text = "
#include "file.txt"
";
    printf("%s", text);
    return 0;
}

Конечно, вам нужно быть осторожным с тем, что на самом деле находится в файле, убедившись, что нет двойных кавычек, что все соответствующие символы экранированы и т. д.

Поэтому было бы проще, если бы вы просто загрузили текст из файла во время выполнения или встроили текст непосредственно в код.

Если вы все еще хотел текст в другом файле, который мог бы быть там, но он должен быть представлен там как строка. Вы использовали бы код, как указано выше, но без двойных кавычек. Например:

"Something evil\n"\
"this way comes!"

int main()
{
    const char* text =
#include "file.txt"
;
    printf("%s", text);
    return 0;
}
4
ответ дан Daemin 15 August 2018 в 23:04
поделиться
  • 1
    Хорошая идея, но это не сработает, либо у вас есть ошибка, потому что буквальный текст включает в себя новую строку, или часть #include будет считана как строка и не выполнена, проклята, если вы это сделаете, и прокляните, если вы этого не сделаете. , – Motti 4 January 2009 в 14:59
  • 2
    @Motti: согласен - как написанный, синтаксически недействительный C. Идея интересная - C-процессор Pre-Process логически является отдельной фазой, но практика заключается в том, что она не выходит из-за того, что каждая строка во включенном файле будет иметь завершение обратным слэшем и т. д. – Jonathan Leffler 4 January 2009 в 17:39
  • 3
    Хамм. Мне кажется, что вам не нужна обратная косая черта, так как большинство компиляторов будут объединять смежные строки вместе – EvilTeach 4 January 2009 в 23:00

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

0
ответ дан Daniel Paull 15 August 2018 в 23:04
поделиться

в x.h

"this is a "
"buncha text"

в main.c

#include <stdio.h>
int main(void)
{
    char *textFileContents =
#include "x.h"
    ;

    printf("%s\n", textFileContents);

    return 0
}

должно выполнить задание.

0
ответ дан EvilTeach 15 August 2018 в 23:04
поделиться
  • 1
    Для нескольких строк вам нужно добавить\n так: & quot; line 1\n & quot; "строка 2\n" – Superfly Jon 27 September 2016 в 10:46

Вы можете сделать это, используя objcopy:

objcopy --input binary --output elf64-x86-64 myfile.txt myfile.o

Теперь у вас есть объектный файл, который вы можете связать с вашим исполняемым файлом, который содержит символы для начала, конца и размера содержимого из myfile.txt.

1
ответ дан John Zwinck 15 August 2018 в 23:04
поделиться

Мне нравится ответ кайара. Если вы не хотите прикасаться к входным файлам, и если вы используете CMake, вы можете добавить последовательности символов деления в файл. Следующий код CMake, например, копирует входные файлы и соответственно переносит их содержимое:

function(make_includable input_file output_file)
    file(READ ${input_file} content)
    set(delim "for_c++_include")
    set(content "R\"${delim}(\n${content})${delim}\"")
    file(WRITE ${output_file} "${content}")
endfunction(make_includable)

# Use like
make_includable(external/shaders/cool.frag generated/cool.frag)

Затем включите в c ++, как это:

constexpr char *test =
#include "generated/cool.frag"
;
0
ответ дан Martin R. 15 August 2018 в 23:04
поделиться

Я думаю, что это невозможно с компилятором и препроцессором. gcc позволяет это:

#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)

    printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
            STRGF(
#               define hostname my_dear_hostname
                hostname
            )
            "\n" );

Но, к сожалению, это не так:

#define _STRGF(x) # x
#define STRGF(x) _STRGF(x)

    printk ( MODULE_NAME " built " __DATE__ " at " __TIME__ " on host "
            STRGF(
#               include "/etc/hostname"
            )
            "\n" );

Ошибка:

/etc/hostname: In function ‘init_module’:
/etc/hostname:1:0: error: unterminated argument list invoking macro "STRGF"
0
ответ дан not-a-user 15 August 2018 в 23:04
поделиться
  • 1
    Я посмотрел, как вы предложили мне посмотреть. Я не вижу никакой новой информации в вашем ответе (информация, которая не находится в других ответах), за ссылкой на /etc/hostname как способ встраивания имени машины сборки в строку, которая (даже если она сработала) не будет переносимым, поскольку Mac OS X не имеет файла /etc/hostname. Обратите внимание, что использование имен макросов, начинающихся с символа подчеркивания, за которым следует заглавная буква, используется имя, зарезервированное для реализации, которое представляет собой Bad Thing ™. – Jonathan Leffler 15 April 2014 в 15:26

Ответ Хастуркуна с использованием опции xxd -i превосходный. Если вы хотите включить процесс преобразования (текст -> файл с шестнадцатеричным включением) непосредственно в свою сборку, то инструмент / библиотека hexdump.c недавно добавила возможность, аналогичную опции -i xxd (она не дает вам полный заголовок - вам нужно для предоставления определения массива char, но это имеет преимущество, позволяя вам выбрать имя массива char):

http://25thandclement.com/~william/projects/hexdump.c .html

Это лицензия намного более «стандартная», чем xxd, и очень либеральная - пример ее использования для вставки файла инициализации в программу можно увидеть в CMakeLists.txt и schem.c здесь:

https://github.com/starseeker/tinyscheme-cmake

Есть плюсы и минусы как для включения сгенерированных файлы в исходных деревьях и связанные с ними утилиты - как справиться с этим будет зависеть от конкретных целей и потребностей вашего проекта. hexdump.c открывает опцию связывания для этого приложения.

0
ответ дан starseeker 15 August 2018 в 23:04
поделиться

Почему бы не связать текст с программой и использовать ее как глобальную переменную! Вот пример. Я рассматриваю возможность использования этого для включения файлов шейдера Open GL в исполняемый файл, поскольку GL-шейдеры должны быть скомпилированы для GPU во время выполнения.

0
ответ дан TechDragon 15 August 2018 в 23:04
поделиться

Вам нужна моя утилита xtr, но вы можете сделать это с помощью bash script. Это сценарий, который я называю bin2inc. Первый параметр - это имя результирующего char[] variable. Второй параметр - имя file. Результатом является C include file с кодированным содержимым файла (в нижнем регистре hex) в качестве имени переменной. char array - zero terminated, а длина данных сохраняется в $variableName_length

#!/bin/bash

fileSize ()

{

    [ -e "$1" ]  && {

        set -- `ls -l "$1"`;

        echo $5;

    }

}

echo unsigned char $1'[] = {'
./xtr -fhex -p 0x -s ', ' < "$2";
echo '0x00'
echo '};';
echo '';
echo unsigned long int ${1}_length = $(fileSize "$2")';'

ВЫ МОЖЕТЕ ПОЛУЧИТЬ XTR ЗДЕСЬ xtr (символ eXTRapolator) - GPLV3

2
ответ дан user 15 August 2018 в 23:04
поделиться

Я переопределял xxd в python3, исправляя все досады xxd:

  • Const correctness
  • string length datatype: int → size_t
  • Null end (в случае, если вы этого захотите)
  • Совместимость с C: Drop unsigned в массиве.
  • Меньший, читаемый вывод, как вы бы его написали: выводится печатный ascii как есть; другие байты кодируются в шестнадцатеричном формате.

Вот сценарий, отфильтрованный сам по себе, поэтому вы можете видеть, что он делает:

pyxxd.c

#include <stddef.h>

extern const char pyxxd[];
extern const size_t pyxxd_len;

const char pyxxd[] =
"#!/usr/bin/env python3\n"
"\n"
"import sys\n"
"import re\n"
"\n"
"def is_printable_ascii(byte):\n"
"    return byte >= ord(' ') and byte <= ord('~')\n"
"\n"
"def needs_escaping(byte):\n"
"    return byte == ord('\\\"') or byte == ord('\\\\')\n"
"\n"
"def stringify_nibble(nibble):\n"
"    if nibble < 10:\n"
"        return chr(nibble + ord('0'))\n"
"    return chr(nibble - 10 + ord('a'))\n"
"\n"
"def write_byte(of, byte):\n"
"    if is_printable_ascii(byte):\n"
"        if needs_escaping(byte):\n"
"            of.write('\\\\')\n"
"        of.write(chr(byte))\n"
"    elif byte == ord('\\n'):\n"
"        of.write('\\\\n\"\\n\"')\n"
"    else:\n"
"        of.write('\\\\x')\n"
"        of.write(stringify_nibble(byte >> 4))\n"
"        of.write(stringify_nibble(byte & 0xf))\n"
"\n"
"def mk_valid_identifier(s):\n"
"    s = re.sub('^[^_a-z]', '_', s)\n"
"    s = re.sub('[^_a-z0-9]', '_', s)\n"
"    return s\n"
"\n"
"def main():\n"
"    # `xxd -i` compatibility\n"
"    if len(sys.argv) != 4 or sys.argv[1] != \"-i\":\n"
"        print(\"Usage: xxd -i infile outfile\")\n"
"        exit(2)\n"
"\n"
"    with open(sys.argv[2], \"rb\") as infile:\n"
"        with open(sys.argv[3], \"w\") as outfile:\n"
"\n"
"            identifier = mk_valid_identifier(sys.argv[2]);\n"
"            outfile.write('#include <stddef.h>\\n\\n');\n"
"            outfile.write('extern const char {}[];\\n'.format(identifier));\n"
"            outfile.write('extern const size_t {}_len;\\n\\n'.format(identifier));\n"
"            outfile.write('const char {}[] =\\n\"'.format(identifier));\n"
"\n"
"            while True:\n"
"                byte = infile.read(1)\n"
"                if byte == b\"\":\n"
"                    break\n"
"                write_byte(outfile, ord(byte))\n"
"\n"
"            outfile.write('\";\\n\\n');\n"
"            outfile.write('const size_t {}_len = sizeof({}) - 1;\\n'.format(identifier, identifier));\n"
"\n"
"if __name__ == '__main__':\n"
"    main()\n"
"";

const size_t pyxxd_len = sizeof(pyxxd) - 1;

Использование (это извлекает скрипт):

#include <stdio.h>

extern const char pyxxd[];
extern const size_t pyxxd_len;

int main()
{
    fwrite(pyxxd, 1, pyxxd_len, stdout);
}
1
ответ дан user2394284 15 August 2018 в 23:04
поделиться

У меня были похожие проблемы, и для небольших файлов вышеупомянутое решение Johannes Schaub работало как прелесть для меня.

Однако для файлов, которые немного больше, он столкнулся с проблемами с массивом символов предел компилятора. Поэтому я написал небольшое приложение кодировщика, которое преобразует содержимое файла в массив двумерных символов с одинаковыми размерами (и, возможно, нулями заполнения). Он создает выходные текстовые файлы с данными 2D-массива, такими как:

const char main_js_file_data[8][4]= {
    {'\x69','\x73','\x20','\0'},
    {'\x69','\x73','\x20','\0'},
    {'\x61','\x20','\x74','\0'},
    {'\x65','\x73','\x74','\0'},
    {'\x20','\x66','\x6f','\0'},
    {'\x72','\x20','\x79','\0'},
    {'\x6f','\x75','\xd','\0'},
    {'\xa','\0','\0','\0'}};

, где 4 фактически является переменной MAX_CHARS_PER_ARRAY в кодере. Затем файл с результирующим C-кодом, называемым, например, «main_js_file_data.h», может легко быть встроен в приложение C ++, например, следующим образом:

#include "main_js_file_data.h"

Вот исходный код кодировщика :

#include <fstream>
#include <iterator>
#include <vector>
#include <algorithm>


#define MAX_CHARS_PER_ARRAY 2048


int main(int argc, char * argv[])
{
    // three parameters: input filename, output filename, variable name
    if (argc < 4)
    {
        return 1;
    }

    // buffer data, packaged into chunks
    std::vector<char> bufferedData;

    // open input file, in binary mode
    {    
        std::ifstream fStr(argv[1], std::ios::binary);
        if (!fStr.is_open())
        {
            return 1;
        }

        bufferedData.assign(std::istreambuf_iterator<char>(fStr), 
                            std::istreambuf_iterator<char>()     );
    }

    // write output text file, containing a variable declaration,
    // which will be a fixed-size two-dimensional plain array
    {
        std::ofstream fStr(argv[2]);
        if (!fStr.is_open())
        {
            return 1;
        }
        const std::size_t numChunks = std::size_t(std::ceil(double(bufferedData.size()) / (MAX_CHARS_PER_ARRAY - 1)));
        fStr << "const char " << argv[3] << "[" << numChunks           << "]"    <<
                                            "[" << MAX_CHARS_PER_ARRAY << "]= {" << std::endl;
        std::size_t count = 0;
        fStr << std::hex;
        while (count < bufferedData.size())
        {
            std::size_t n = 0;
            fStr << "{";
            for (; n < MAX_CHARS_PER_ARRAY - 1 && count < bufferedData.size(); ++n)
            {
                fStr << "'\\x" << int(unsigned char(bufferedData[count++])) << "',";
            }
            // fill missing part to reach fixed chunk size with zero entries
            for (std::size_t j = 0; j < (MAX_CHARS_PER_ARRAY - 1) - n; ++j)
            {
                fStr << "'\\0',";
            }
            fStr << "'\\0'}";
            if (count < bufferedData.size())
            {
                fStr << ",\n";
            }
        }
        fStr << "};\n";
    }

    return 0;
}
0
ответ дан volzo 15 August 2018 в 23:04
поделиться
14
ответ дан Community 5 September 2018 в 22:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: