Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Бинарные файлы

Ответить
Настройки темы
C/C++ - Бинарные файлы

Новый участник


Сообщения: 21
Благодарности: 1

Профиль | Отправить PM | Цитировать


Изменения
Автор: .::.DIMA.::.
Дата: 16-03-2013
Решено

Отправлено: 12:52, 20-04-2009

 
pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Цитата .::.DIMA.::.:
Как можно прочитать бинарный файл »
Строчка, содержащая в том числе неаскишные символы, либо как последовательность однобайтовых чисел
Цитата .::.DIMA.::.:
1 символ - 1 байт »
Совершенно верно
В паскале рекомендую использовать array of char, в c++ vector<unsigned char>
Это сообщение посчитали полезным следующие участники:

Отправлено: 15:12, 20-04-2009 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

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

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Код: Выделить весь код
// с
int file_size = ...;

unsigned char* mem = (unsigned char*)malloc(file_size);
fread(mem, 1, file_size, my_file);


// c++
filebuf buf;
buf.open("my_file.txt", ios::in|ios::binary);

vector<unsigned char> mem(file_size);
mem.resize(buf.sgetn(&mem[0], file_size));
Это сообщение посчитали полезным следующие участники:

Отправлено: 13:58, 21-04-2009 | #3


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


.::.DIMA.::., fread нет необходимости знать структуру
К примеру по ссылке можно добавить следующий код, что б увидеть, а что хоть считало
Код: Выделить весь код
/* the whole file is now loaded in the memory buffer. */
//...
for (int i=0;i<result;i++)
	printf("%c",buffer[i]);
//...
// terminate
В случаи с fwrite всё аналогично.
В случае с fprintf / fscanf нужно задавать параметр считывания, впрочем можно ведь задать как unsigned char, а уже в цикле как по приведённом выше коде, распознать что есть что.
pva, в случаи символа, как наименьшего элемента файла, один символ = один байт.
А вот в случаи с UNICODE текста - один печатный символ уже не один байт.

Последний раз редактировалось Admiral, 21-04-2009 в 14:47.

Это сообщение посчитали полезным следующие участники:

Отправлено: 14:08, 21-04-2009 | #4

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Цитата Admiral:
pva, в случаи символа, как наименьшего элемента файла, один символ = один байт.
А вот в случаи с UNICODE текста - один печатный символ уже не один байт. »
Мы ведь воспринимаем бинарные данные, я просто взял наименьшую неделимую единицу объёма памяти. А так можно было и 8-байтными double читать. А можно было и как текстовую базу данных:
Код: Выделить весь код
struct row_t {
   char id[8];
   char name[100];
   char description[255];
   char _reserved_for_DOS_CR[2];
};

...

row_t row1[10];
fread(row1, sizeof(row_t), 10, file);
Это сообщение посчитали полезным следующие участники:

Отправлено: 07:38, 22-04-2009 | #5


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


pva насчёт юникода, тут есть пользовательский момент: если воспользоваться примером выше для чтения файла сохранённого в Юникоде, то после каждого символа будут пробелы (текст на английском, для других языков не проверял). Это удивит пользователя, который не будет наблюдать последних при просмотреть через блокнот. В этом случаи, как я понимаю, или самостоятельно убирать пробелы, или же юзать юникод версии функций чтения/записи и соответственные пользовался переменными типа wchar_t.

Хорошо что привели структуру, хотелось бы её обсудить.
Если её натравить на любой текстовый файл, то вывод будет в виде абракадабры
Цитата Фрагмент данных прочитанных с файла boot.ini приведённым примером:
╠╠Ё:B
Это вполне логично, ведь как известно при чтении/записи структуры fread/fwrite оперирует с так называемыми "сырыми" данными.
Цитата Фрагмент данных с сохраненного программой ниже файла, при просмотре Word'ом:
id0 ММММname0
У блокнота на это счёт был другой вариант с многократным использованием символа [] и цифр.
И дело тут не в режиме открытия t/b, которые отличаются только тем, что в первом случаи перевод каретки (Ентер) и новая строчка это один символ, а во втором два отдельных, а в том что так оно устроено.
Собственно сама программа чтения/записи, с использованиям приведённой структуры.
Поля, да и сама структура, используются явно не по назначению, приведено только для примера.
Код: Выделить весь код
#include <stdio.h>
#include <stdlib.h>

	struct row_t
	{
	char id[8];
	char name[100];
	char description[255];
	char _reserved_for_DOS_CR[2];
	};

int main(int argc, char* argv[])
{

	row_t row1[10];
	int i;
		for (i=0;i<10;i++)
		{
			sprintf(row1[i].id,"id%d",i);
			sprintf(row1[i].name,"name%d",i);
			sprintf(row1[i].description,"description%d",i);
			sprintf(row1[i]._reserved_for_DOS_CR,"R%d",i);
		}
			
	if (argc>1)
	{
		FILE * pFile = fopen ( argv[1] , "wb+" );
		if (pFile==NULL) 
		{
			printf ("File error"); 
			return -1;
		}
		
	
		fwrite(row1, sizeof(row_t), 10, pFile);
		rewind(pFile);
		
		for (i=0;i<10;i++)
		{
			sprintf(row1[i].id,"%d",i);
			sprintf(row1[i].name,"%d",i);
			sprintf(row1[i].description,"%d",i);
			sprintf(row1[i]._reserved_for_DOS_CR,"%d",i);
		}

		fread(row1, sizeof(row_t), 10, pFile);
		for (i=0;i<10;i++)
			printf("%s %s %s %s\n", row1[i].id, row1[i].name, row1[i].description, row1[i]._reserved_for_DOS_CR);
		fclose (pFile);
	}
	return 0;
}
Использование: набрать в командной строке prog.exe somefile.dat, где имя программы соответственное, имя файла любое. Будут создан автоматически.
Цитата Вывод программы:
id0 name0 description0 R0id1
id1 name1 description1 R1id2
id2 name2 description2 R2id3
id3 name3 description3 R3id4
id4 name4 description4 R4id5
id5 name5 description5 R5id6
id6 name6 description6 R6id7
id7 name7 description7 R7id8
id8 name8 description8 R8id9
id9 name9 description9 R9
Мне не понятно, почему идёт захват следующего элемента, я про R0id1 когда должен был выведен только R0
При отладки в некоторых средах может появляется сообщение о разрушении стека возле переменной row1.
Цитата:
Run-Time Check Failure #2 - Stack around the variable 'row1' was corrupted.
Избавится от него можно уменьшив в начале программы количество заполняемых элементов массива или убрав заполнение элемента структуры _reserved_for_DOS_CR.
Причём то что далее по тексту идёт затирание чрез i (для того что б убедится что данные берутся именно из файла) всех элементов структуры и элементов массива (от 0 до 10 не включая 10) row1 среда не находит проблемным.

Структуры удобны в обработке, но в текстовом виде данные в файлы не сохранишь. Или всё же можно?
Это сообщение посчитали полезным следующие участники:

Отправлено: 18:47, 22-04-2009 | #6

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Цитата Admiral:
выше для чтения файла сохранённого в Юникоде »
Изначально речь шла о двоичном представлении (и возможно уникода, но не обязательно), хотя может я пропустил какие-то детали
Цитата Admiral:
или самостоятельно убирать пробелы »
Это не пробелы, а байт 0, т.к. для символов ascii значение не превышает 127, а в 16-битном представлении это даёт старший нулевой байт
Цитата Admiral:
оперирует с так называемыми "сырыми" данными. »
не согласен, они так не называются, эти функции оперируют с содержимым памяти (независимо от представления её в программе)
Цитата Admiral:
Или всё же можно? »
можно всё на свете. Современные компиляторы уже не ограничивают фантазию программиста.
Пример: запускаем FAR, создаём в нём текст, который содержит ровно 20 строк ровно по 8 + 100 + 255 = 363 символа (пробела). Включаем режим замены (нажимаем INSERT) и заполняем полученные строки (так чтобы длина строки оставалась 363, а "пустые" символы заполнялись пробелами) Начиная с каждого 0 символа строки пишем ID, с каждого 8 name, со 108 - description. На вид получится красивая выровненная табличка. Сохраняем файл и подаём в качестве аргумента к программе. Должно отработать красиво.
Конечно же не оптимально хранить данные в таких файлах, где много пробелов, тем не менее, бывают случаи когда это самое элегантное решение, не требующее сложной обработки данных. Например рассмотрим телефонную станцию, после каждого звонка выдаёт следующие строчки:
1. дата (8 симв, ддммгггг)
2. время (6 символов ччммсс)
3. исходящий номер (11 симв)
4. входящий номер (11 симв)
5. время разговора (4 симв)
6. стоимость разговора (10 симв)
вот в таком виде:
Код: Выделить весь код
220420092259148916342111189076958093 120      4500
220420092304548916342111189076958093 120      4500
Теперь по поводу ошибок в программе:
Код: Выделить весь код
// думаю причина в использовании аргумента %s с не Null-terminated string
// правильный вариант:
void print_row(row_t* row)
{
   printf("%8s|%100s|%255s|\n", row->id, row->name, row->description);
//   static const char* space = "|";
//   fwrite(row->id, sizeof(row->id), 1, stdout);
//   fwrite(space, 1, 1, stdout);
//   fwrite(row->name, sizeof(row->name), 1, stdout);
//   fwrite(space, 1, 1, stdout);
//   fwrite(row->description, sizeof(row->description), 1, stdout);
//   fwrite(space, 1, 1, stdout);
}
Это сообщение посчитали полезным следующие участники:

Отправлено: 21:18, 22-04-2009 | #7


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


pva, это про то, как с точки зрения пользователя будет работать программа, читающие так текстовые файлы.
Опять использовал пользовательскую терминологию, на экране он видит пробелы.
Спасибо за ликбез, буду знать - "байт 0".


Говоря "сырые" я использую терминологию применяемую Харви и Полом Дейтелем, может быть дело в переводе. Тогда мне не понятно, почему находясь в памяти компьютера эти данные имеют читабельный вид, а сохраняясь в файл преображаются в не читаемый вид?

А почему именно 20? У нас ведь массив на 109.

Чёткость не меньше/не больше, в данном случаи в файле 20 строк, не совсем согласуется с тем, что данные в файле могут свободно обновляться, в том числе сторонней программой, например через блокнот пользователём.

К сожалению отображение не получилось
в виде чёткой таблицы
ID name description
01 and description
02 asm description
03 auto description
04 bitand description
05 bitor description
06 bool description
07 break description
08 case description
09 catch description
10 char description
11 class description
12 compl description
13 const description
14 const_cast description
15 continue description
16 default description
17 delete description
18 do description
19 double description

Код: Выделить весь код
#include <stdio.h>

struct row_t
{
	char id[8];
	char name[100];
	char description[255];
	char _reserved_for_DOS_CR[2];
};

int main(int argc, char* argv[])
{
	if (argc>1)
	{
		FILE * pFile = fopen ( argv[1] , "rb" );
		if (pFile==NULL) 
		{
			printf ("File error"); 
			return -1;
		}

		row_t row1[10];
		fread(row1, sizeof(row_t), 10, pFile);
		for (int i=0;i<10;i++)
			printf("%s %s %s", row1[i].id, row1[i].name, row1[i].description);
		fclose (pFile);
	}
	return 0;
}
А можно ли вместо пробелов применять разделять данные элементов структуры табуляцией? Простой пример - таблицы в Екселе: сохраняем в табулированный файл и обрабатываем в программе.

Последний раз редактировалось Admiral, 12-12-2009 в 04:21. Причина: Содержимое откреплённых вложений перенёс в пост

Это сообщение посчитали полезным следующие участники:

Отправлено: 01:48, 23-04-2009 | #8

pva pva вне форума

Аватара для pva

Ветеран


Сообщения: 1180
Благодарности: 279

Профиль | Отправить PM | Цитировать


Цитата Admiral:
Тогда мне не понятно, почему находясь в памяти компьютера эти данные имеют читабельный вид, а сохраняясь в файл преображаются в не читаемый вид? »
Дело в том, что во время чтения "в читабельном виде", эти данные реально находятся в памяти (программа-просмотрщик перед отрисовкой на экран читает их из файла), а "читабельность" зависит от представления данных в программе. Например:
Код: Выделить весь код
union
{
   double d;
   char c[8];
} value1;

value1.d = 0.1;
// используем одну и ту же память:
printf("%8s", value1.c); // получим галиматью
printf("%8lf", value1.d); // получим красоту
printf("%8ld", value1.d); // в "с" это можно сделать :( получим галиматью

// получим 16-ричное представление памяти, в которой лежит double(0.1)
cout << hex << setfill('0') ;
for(unsigned i=0; i<8; ++i) cout << setw(2) << static_cast<unsigned>(reinterpret_cast<unsigned char>(c[i])) << " ";
Цитата Admiral:
А почему именно 20? У нас ведь массив на 109. »
задавая структуру row_t я ограничил размер неделимого блока файла (сохранающий работоспособность программы) до 365 байт. Других ограничений нет. Можно загрузить за раз 20 строчек, можно 50, а можно 1. Главное соблюдать в программе нерушимость памяти.
Цитата Admiral:
Чёткость не меньше/не больше, в данном случаи в файле 20 строк, не совсем согласуется с тем, что данные в файле могут свободно обновляться, в том числе сторонней программой, например через блокнот пользователём »
Если пользователю давать работать с файлом только через программу, то всё будет ок! А уронить ручкми можно любой файл.
Цитата Admiral:
К сожалению отображение не получилось в виде чёткой таблицы (применяемы файл данных и код программы, для чистоты эксперимента, без исправлений вывода, во вложении). »
Я поправил файл (нам строчки были разной длины). В скриншоте всё выглядит достаточно ровно

Последний раз редактировалось pva, 25-02-2012 в 11:59.

Это сообщение посчитали полезным следующие участники:

Отправлено: 08:55, 23-04-2009 | #9


Ветеран


Сообщения: 3320
Благодарности: 916

Профиль | Отправить PM | Цитировать


pva, возможно покажусь назойливым, но всё же, возможно ли структуру в читабельном виде сохранить в файл, что б при чтении обратно программа понимала что это структура? В примерах про структуры показывается что нет - только бинарное представление.
В каких случаях стоит использовать union(объединение)? Это ведь таже структура, только более щадящая память за счёт размещения всех полей по одному и тому же адресу.


Вместо пробелов всё же хочется задействовать табуляцию. В качестве примера я взял предыдущий - про телефонную станцию.
Вот её структура
Код: Выделить весь код
struct PhoneStatistic
{
char date[8+1];		//1. дата (8 симв, ддммгггг)
char time[6+1];		//2. время (6 символов ччммсс)
char dialing[11+1];	//3. исходящий номер (11 симв)
char incoming[11+1];	//4. входящий номер (11 симв)
char duration[4+1];	//5. время разговора (4 симв)
char price[10+1];	//6. стоимость разговора (10 симв)
char *notes;		//7. новое поле переменно не определённой/не известной длины для эксперимента
};
ещё один прибавляем для NULL символа
Визуально всё хорошо получается (используя printf), да вот возникает сложность сбора данных в поля структуры.

Используя printf можно в цикле выводить символы, при этом на экране складывается слово. По идеи, тоже самое можно сделать для полей структуры через sprintf. Да вот не задачка, не проходит.

stdout это стандартный поток вывод, а stdin - ввода. Возможно, ли каким-то образом используя их комбинацию заполнять поля структуры данными выводимыми printf'ом? То есть что б они брались с экрана?

Возможно ли во время выполнения программы узнать количество полей/элементов структуры? Так как в программе приходится за каждым элементом закреплять свой цикл.

Код, построенный на примере про fread по ссылке выше
Код: Выделить весь код
/* fread example: read a complete file */

#include <stdio.h>
#include <stdlib.h>
//#include <string.h>

#define CR	0x0d	//Возврат каретки
#define SP	0x20	//Пробел

struct PhoneStatistic
{
	char date[8+1];		//1. дата (8 симв, ддммгггг)
	char time[6+1];		//2. время (6 символов ччммсс)
	char dialing[11+1];	//3. исходящий номер (11 симв)
	char incoming[11+1];//4. входящий номер (11 симв)
	char duration[4+1];	//5. время разговора (4 симв)
	char price[10+1];	//6. стоимость разговора (10 симв)
	char *notes;		//7. новое поле переменно не определённой/не известной длины для эксперимента
};

int main(int argc, char* argv[])
{
	if (argc<=1)
	{
		printf("\nUsage: %s <File Name>",argv[0]);
		return 0;
	}

	FILE * pFile;
	long lSize;
	char * buffer;
	size_t result;
	
	pFile = fopen ( argv[1] , "rb" );
	if (pFile==NULL) {fputs ("File error",stderr); exit (1);}

	// obtain file size:
	fseek (pFile , 0 , SEEK_END);
	lSize = ftell (pFile);
	rewind (pFile);

	// allocate memory to contain the whole file:
	buffer = (char*) malloc (sizeof(char)*lSize);
	if (buffer == NULL) {fputs ("Memory error",stderr); exit (2);}

	// copy the file into the buffer:
	result = fread (buffer,1,lSize,pFile);
	if (result != lSize) {fputs ("Reading error",stderr); exit (3);}

	/* the whole file is now loaded in the memory buffer. */
	fclose (pFile);

	unsigned int i;
	unsigned int Tabs=0;
	unsigned int Enters=0;
	unsigned int Newlines=0;
	unsigned int Spaces=0;

	for (i=0;i<result;i++)
	{
		//printf("%c",buffer[i]);
		/*Если раскомментировать строчку выше,
		то всё что после данного цикла до free (buffer);
		можно убрать и визуально вывод не пострадает.*/
		switch (buffer[i])
			{
			case '\t': Tabs++; break;
			case '\n': Enters++; break;
			case CR: Newlines++; break;
			case SP: Spaces++; break;
			default: break;
			}
	}
	printf("\t\tStatistics\n Pages *\n Words *\n Characters \t\t\t%i\n Characters (with spaces) \t%i\n Tabs \t\t\t\t%i\n Entered \t\t\t%i\n Lines \t\t\t\t%i\n Spaces \t\t\t%i\n",i-Spaces,i-Enters,Tabs,Enters,Newlines,Spaces);
	
	PhoneStatistic *currentStatistic = new PhoneStatistic[Newlines];
	/*Возможно покажется что данные булевые переменные,
	но они рассчитаны, по крайне мере запланированы,
	на тот случай если структура файла будет нарушена*/
	bool lockDate = false;
	bool lockTime = true;
	bool lockDialing = true;
	bool lockIncoming = true;
	bool lockDuration = true;
	bool lockPrice = true;
	bool lockNotes = true;
	//unsigned int j;

	for(i=0;i<result;i++)
	{
		while ((buffer[i]!='\t') && (!lockDate))
		{
			if (buffer[i]=='\n') break;
			printf("%c",buffer[i]);
			i++;
		}
		lockDate = true;
		printf("%c",buffer[i]);//здесь и дальше вне циклов while будет вывод для визуальной разметки, табуляции и символы новой строки
		i++;
		lockTime = false;

		while ((buffer[i]!='\t') && (!lockTime))
		{
			if (buffer[i]=='\n') break;
			printf("%c",buffer[i]);
			//sprintf(currentStatistic[j].time,"%c",buffer[i]);
			//printf("%c",currentStatistic[j].time);
			i++;
		}

		lockTime = true;
		printf("%c",buffer[i]);
		i++;
		lockDialing = false;
	
		while ((buffer[i]!='\t') && (!lockDialing))
		{
			if (buffer[i]=='\n') break;
			printf("%c",buffer[i]);
			//sprintf(currentStatistic[j].dialing,"%c",buffer[i]);
			//printf("%c",currentStatistic[j].dialing);
			i++;
		}
		
		lockDialing = true;
		printf("%c",buffer[i]);
		i++;
		lockIncoming = false;

		while ((buffer[i]!='\t') && (!lockIncoming))
		{	if (buffer[i]=='\n') break;
			printf("%c",buffer[i]);	
			//sprintf(currentStatistic[j].incoming,"%c",buffer[i]);
			//printf("%c",currentStatistic[j].incoming);
			i++;
		}
		
		lockIncoming = true;
		printf("%c",buffer[i]);
		i++;
		lockDuration = false;
		
		while ((buffer[i]!='\t') && (!lockDuration))
		{	if (buffer[i]=='\n') break;
			printf("%c",buffer[i]);	
			//sprintf(currentStatistic[j].duration,"%c",buffer[i]);
			//printf("%c",currentStatistic[j].duration);
			i++;
		}
	
		lockDuration = true;
		printf("%c",buffer[i]);
		i++;
		lockPrice = false;
		
		while ((buffer[i]!='\t') && (!lockPrice))
		{	if (buffer[i]=='\n') break;
			printf("%c",buffer[i]);	
			//sprintf(currentStatistic[j].price,"%c",buffer[i]);
			//printf("%c",currentStatistic[j].price);
			i++;
		}

		lockPrice = true;
		printf("%c",buffer[i]);
		i++;
		lockNotes = false;
		
		while ((buffer[i]!='\n') && (!lockNotes))
		{
			if (i==result) break;
			printf("%c",buffer[i]);
			//sprintf(currentStatistic[j].notes,"%c",buffer[i]);
			//printf("%c",currentStatistic[j].notes);
			i++;
		}

		//if (buffer[i]=='\n') j++;
		if (i==result) break;
		lockNotes = true;
		printf("%c",buffer[i]);
		//i++; Дадим циклу for увеличить счётчик :)
		lockDate = false;
	}
	free (buffer);
	//currentStatistic if ((buffer[i]!=CR)/*0x0d*/
	//printf("\n");
	
	//for (int j=0;j<Newlines;j++)
	//	printf("%s",currentStatistic[j].date);
		
	return 0;
}

Пример статистики
22042009 225914 89163421111 89076958093 120 4500 importante
22042009 230454 89163421111 89076958093 120 4500 secure

Отличие, от данных которые привёл
pva выше - в добавленной табуляции между полями + новое поле.

Последний раз редактировалось Admiral, 12-12-2009 в 04:32. Причина: Содержимое откреплённых вложений перенёс в пост

Это сообщение посчитали полезным следующие участники:

Отправлено: 20:29, 25-04-2009 | #10



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » C/C++ - Бинарные файлы

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Не открываются текстовые файлы и изображения и к ним создались файлы с расшир. drweb leda Лечение систем от вредоносных программ 1 03-10-2009 01:22
[решено] Не удаляются неизвестные мне файлы fidbox.dat и fidbox.idx. Что это за файлы? segafos Лечение систем от вредоносных программ 31 04-06-2009 17:17
CMD/BAT - файлы вида mmdd*.* - для каждой даты нужно создать каталог, скопировать, файлы milito Скриптовые языки администрирования Windows 2 24-05-2009 23:32
Доступ - html-файлы грузятся как файлы для скачивания Dr. MefistO Microsoft Windows 2000/XP 1 08-03-2009 10:06
Файлы Surround Вебмастеру 4 28-03-2003 08:35




 
Переход