Сохранение данных в двоичный файл - PullRequest
1 голос
/ 13 апреля 2011

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

Сейчас я пытаюсь сохранить бинарный файл с некоторым текстом, но проблема в том, что файл просто содержит текст и NULL в конце. Я ожидаю увидеть только нули и единицу внутри файла.

Любые объяснения или предложения высоко ценятся.

Вот мой код

#include <iostream>
#include <stdio.h>

int main()
{
     /*Temporary data buffer*/
     char buffer[20];

     /*Data to be stored in file*/
     char temp[20]="Test";

     /*Opening file for writing in binary mode*/
     FILE *handleWrite=fopen("test.bin","wb");

     /*Writing data to file*/
     fwrite(temp, 1, 13, handleWrite);

     /*Closing File*/
     fclose(handleWrite);

    /*Opening file for reading*/
    FILE *handleRead=fopen("test.bin","rb");

    /*Reading data from file into temporary buffer*/
    fread(buffer,1,13,handleRead);

    /*Displaying content of file on console*/
    printf("%s",buffer);

    /*Closing File*/
    fclose(handleRead);
    std::system("pause");

    return 0;
}

Ответы [ 6 ]

12 голосов
/ 13 апреля 2011

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

Существует существенная разница междупонятия символа кодировка и символа набор .Пока вы действительно не поймете эту разницу, вы никогда не поймете, что происходит здесь.Джоэл Спольски (один из основателей Stackoverflow, если подумать об этом) недавно написал статью, объясняющую разницу: Абсолютный минимум каждый разработчик программного обеспечения Абсолютно, положительно должен знать о Unicode и наборах символов (без оправданий!).Прежде чем продолжить читать, прежде чем продолжить программирование, даже прочитайте это.Честно, почитай, пойми: название не преувеличено.Вы должны точно знать это.

После этого давайте продолжим:

Когда программа на C запускается, в ячейке памяти, которая должна содержать значение типа "char", содержится толькокак и любая другая ячейка памяти, последовательность единиц и нулей.«Тип» переменной означает что-то только для компилятора, а не для работающей программы, которая просто видит единицы и обнуляет и не знает больше этого.Другими словами: если вы обычно думаете о «букве» (элементе из символа set ), находящемся где-то в памяти, то, что на самом деле есть битовая последовательность (элемент из кодировки символа )).

Каждый компилятор может использовать любую кодировку, которую он желает представлять символами в памяти.Как следствие, он может представлять то, что мы называем «новой строкой» внутри себя, как любое выбранное число.Например, скажем, я пишу компилятор, я могу согласиться с тем, что каждый раз, когда я хочу сохранить внутреннюю «новую строку», я сохраняю ее как число шесть (6), что составляет просто 0x6 в двоичном (или 110 в двоичном).

Запись в файл выполняется сообщением операционной системы 2 о четырех вещах одновременно:

  • Тот факт, что вы хотите записать в файл (fwrite())
  • Где начинаются данные, которые вы хотите записать (первый аргумент fwrite)
  • Сколько данных вы хотите записать (второй и третий аргумент, умноженные)
  • В какой файл вы хотите записать (последний аргумент)

Обратите внимание, что это не имеет никакого отношения к «типу» этих данных: ваша работа не имеет представления и не заботится,Он ничего не знает о наборах символов и ему все равно: он просто видит последовательность единиц и нулей, начинающихся где-то, и копирует их в файл.

Открытие файла в «двоичном» режиме на самом деле является нормальнымИнтуитивно понятный способ работы с файлами, который может ожидать начинающий программист: указанная вами область памяти копируется один в один в файл.Если вы записываете в память место, которое использовалось для хранения переменных, которые компилятор решил сохранить как тип «char», эти значения записываются в файл один на один.Если вы не знаете, как компилятор хранит значения внутри себя (какое значение он связывает с символом новой строки, с буквой «a», «b» и т. Д.), ЭТО ЗНАЧИТЕЛЬНО.Сравните это с аналогичным замечанием Джоэла о том, что текстовый файл бесполезен, не зная, какова его кодировка: то же самое.

Открытие файла в «текстовом» режиме почти равно бинарному режиму, с одним (и только одним) отличием: каждый раз, когда записывается значение, значение которого равно тому, что компилятор использует ВНУТРЕННИЙ для новой строки (6, в нашемcase), он записывает в файл что-то другое: не то значение, а то, какую операционную систему вы используете, считает новой строкой.В Windows это два байта (13 и 10 или 0x0d 0x0a в Windows).Заметьте, опять же, если вы не знаете о выборе компилятором внутреннего представления других символов, это ПОСТОЯННО БЕЗУМНО.

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

(Un) К счастью, большинство (все?) Компиляторов фактически используют одно и то же внутреннее представление для символов: это представление US-ASCII и является матерью всех значений по умолчанию.По этой причине вы можете записать некоторые «символы» в файл в вашей программе, скомпилированный любым произвольным компилятором, а затем открыть его с помощью текстового редактора: все они используют / понимают US-ASCII, и это работает.

Хорошо, теперь, чтобы связать это с вашим примером: почему нет разницы между написанием «теста» в двоичном режиме и в текстовом режиме? Поскольку в "test" нет новой строки, вот почему!

И что это значит, когда вы "открываете файл", а затем "видите" символы?Это означает, что программа, которую вы использовали для проверки последовательности единиц и нулей в этом файле (потому что на вашем жестком диске все равно единице и нулю) решила интерпретировать это как US-ASCII, и именно это ваш код компилятор решил закодироватьэта строка как, в ее памяти.

Бонусные пункты: напишите программу, которая считывает единицы и нули из файла в память и печатает каждый бит (есть несколько битов, чтобы составить один байт, для их извлечения вам нужночтобы узнать хитрые операторские трюки, Google!) как «1» или «0» для пользователя.Обратите внимание, что «1» - это ХАРАКТЕР 1, точка в выбранном вами наборе символов, поэтому ваша программа должна взять бит (число 1 или 0) и преобразовать его в последовательность битов, необходимых для представления символа 1 или 0 вкодирование, которое использует эмулятор терминала, что вы просматриваете стандарт из программы на Боже мой.Хорошая новость: вы можете использовать множество коротких путей, допуская US-ASCII везде.Эта программа покажет вам, что вы хотели: последовательность единиц и нулей, которую ваш компилятор использует для внутреннего представления «теста».

Этот материал действительно пугающий для новичков, и я знаю, что это заняло у меня много временидаже знать, что было разницей между набором символов и кодировкой, не говоря уже о том, как все это работало.Надеюсь, я не демотивировал тебя, если бы я это сделал, просто помни, что ты никогда не сможешь потерять знания, которые у тебя уже есть, только получить их (хорошо, не всегда так: P).В жизни нормально, что в заявлении возникает больше вопросов, чем в ответе. Сократ знал это, и его мудрость беспрепятственно применима к современным технологиям спустя 2,4 тыс. Лет.

Удачи, не стесняйтесь продолжать задавать вопросы.Другим читателям: пожалуйста, улучшайте этот пост, если вы видите ошибки.

Hraban

1 Человек, который сказал вам, что "сохранение файла в двоичном формате, вероятно,меньше », например, вероятно серьезно неправильно понимает эти основы.Если только он не имел в виду сжатие данных перед тем, как сохранить их, в этом случае он просто использует запутанное слово («двоичный») для «сжатый».

2 , сообщающий операционной системе"что-то" - это то, что обычно называют системным вызовом.

12 голосов
/ 13 апреля 2011

Все файлы содержат только единицы и нули, на двоичных компьютерах это все, с чем можно играть.

Когда вы сохраняете текст, вы сохраняете двоичное представление этого текста в заданной кодировке , которая определяет, как каждая буква отображается в битах.

Так что для текста текстовый файл или двоичный файл почти не имеет значения; экономия места, о которой вы слышали, обычно используется для других типов данных.

Рассмотрим число с плавающей запятой, например 3.141592653589. Если сохранить как текст, это займет один символ на цифру (просто посчитать их), плюс период. Если сохранить в двоичном виде как просто копию битов float, в обычной 32-битной системе потребуется четыре символа (четыре байта или 32 бита). Точное количество битов, хранящихся при вызове, таких как:

FILE *my_file = fopen("pi.bin", "wb");
float x = 3.1415;
fwrite(&x, sizeof x, 1, my_file);

равно CHAR_BIT * sizeof x, см. <stdlib.h> для CHAR_BIT.

2 голосов
/ 13 апреля 2011

Ну, разница между нативным и бинарным способом обработки конца строки. Если вы напишите строку в двоичном файле, она останется строкой.

Если вы хотите уменьшить его, вам придется каким-то образом сжать его (например, поискать libz).

Что меньше: если вы хотите сохранить двоичные данные (например, массив байтов), то меньше, чтобы сохранить их как двоичные данные, а не помещать их в строку (либо в виде hexa, либо в base64) Надеюсь, это поможет.

1 голос
/ 13 апреля 2011

Я думаю, вы здесь немного запутались.

ASCII-строка «Test» по-прежнему будет ASCII-строкой, когда вы записываете ее в файл (даже в двоичном режиме). Случаи, когда имеет смысл писать двоичные файлы, относятся к другим типам, кроме символов (например, массив целых чисел).

0 голосов
/ 13 апреля 2011

Функция printf ("% s", буфер);печатает буфер как строку с нулевым окончанием

Попробуйте использовать: char temp [20] = "Test \ n \ rTest";

0 голосов
/ 13 апреля 2011

попробуйте заменить

FILE *handleWrite=fopen("test.bin","wb");
fwrite(temp, 1, 13, handleWrite);

на

FILE *handleWrite=fopen("test.bin","w");
fprintf(handleWrite, "%s", temp);
...