Записывать необработанную двоичную структуру в файл в D?
Я пытаюсь создать двоичный файл, содержащий несколько двоичных записей, определенных в некоторых struct
. Однако я не могу найти, как это сделать. Посмотрев на другие примеры, мне удалось написать string
s без проблем, но нет struct
. Я просто хочу написать его, как в случае C
с fwrite(3)
, но в D
версии 2.
Вот что я пробовал до сих пор:
- using
stream.write(tr)
- записывает удобочитаемое / отладочное представление - using
stream.rawWrite(tr)
- это звучало как то, что мне нужно, но не компилируется с помощью:
Ошибка: шаблон std.stdio.File.rawWrite не может выводить функцию из типов аргументов! () (TitleRecord), кандидатами являются:
/usr/lib/ldc/x86_64-linux-gnu/include/d/std/stdio.d(1132): std.stdio.File.rawWrite (T) (в буфере T [])
- пытаясь,
rawWrite
как указано выше, но приводя данные к разным вещам, также никогда не компилируется. - даже пытается вернуться к
C
сfwrite
, но не может получить достаточно глубоко , чтобы получить дескриптор файла I необходимость.
Чтение документации не очень помогло (мне тоже подходит написание строк, но не написание struct
). Я уверен, что должен быть простой способ сделать это, но я не могу его найти .... Другие ТАК вопросы мне не помогли . Я D 1.0
, возможно, это было бы сделано, stream.writeExact(&tr, tr.sizeof)
но это уже не вариант.
import std.stdio;
struct TitleRecord {
short id;
char[49] text;
};
TitleRecord tr;
void main()
{
auto stream = File("filename.dat","wb+");
tr.id = 1234;
tr.text = "hello world";
writeln(tr);
//stream.write(tr);
//stream.rawWrite(tr);
//stream.rawWrite(cast(ubyte[52]) tr);
//stream.rawWrite(cast(ubyte[]) tr);
//fwrite(&tr, 4, 1, stream);
}
Ответы
Для этого эта ошибка говорит, что ожидает массив, а не структуру. Один из простых способов сделать это - просто нарезать указатель и передать его rawWrite:
stream.rawWrite((&tr)[0 .. 1]);
(&tr)
Получает адрес, превращая ваш - структуру на указатель. Затем [0 .. 1]
средства получают кусочек этого с самого начала, захватывая только один элемент.
Таким образом, теперь у вас есть объект, T[]
который rawWrite может обрабатывать, содержащий ваш единственный элемент.
Имейте в виду, что если вы используете @safe
аннотацию, это не пройдет, вам придется ее отметить @trusted
. Также, конечно, любые ссылки внутри вашей структуры (в том числе string
) будут записаны как двоичные указатели вместо данных, как вы наверняка знаете из опыта C. Но в том случае, если вы там показали, все в порядке.
edit: Кстати, вы также можете просто использовать, fwrite
если хотите, скопировать / вставить тот же код из C (за исключением того, что это foo.sizeof
вместо sizeof foo
). Элемент D File
- это просто небольшая оболочка вокруг C, FILE*
и вы можете получить исходный ФАЙЛ * обратно, чтобы передать его другим функциям с помощьюstream.getFP()
http://dpldocs.info/experimental-docs/std.stdio.File.getFP.html )
rawWrite
ожидает массив, но есть много обходных путей.
Один из них - создать массив из одного элемента.
file.rawWrite([myStruct]);
Другой преобразует структуру в массив. В моей библиотеке bitleveld есть функция для этого reinterpretAsArray
. Это также упрощает создание контрольных сумм указанных структур.
Время от времени я сталкивался с проблемами при выравнивании с помощью этого метода, поэтому будьте осторожны. Можно исправить, изменив align
свойство структуры.