Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 22.11.2013, 00:01   #1
3Doleg
Пользователь
 
Регистрация: 03.10.2012
Сообщений: 67
По умолчанию способы удаления из файла

Здраствуйте, есть такой вопрос:
как еще можно организовать удаления записи из файла, но без дополнительного файла, и без массива(буфера), если
кто знает, буду благодарен за алгоритм)
P.s:файл типизированый
3Doleg вне форума Ответить с цитированием
Старый 22.11.2013, 00:06   #2
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

если нужно удалить K-ю запись, то можно в цикле переписать K+1 элемент на место K, K+2 на место K+1 и т.д. до последнего элемента массива.
Потом командой truncate обрезать файл по предпоследнюю запись включительно.
Всё.



p.s. способ и неэффективный и "опасный" - малейший сбой во время цикла и всё - прощай файл..
Поэтому вариант с созданием дополнительного файла более предпочтителен.
А ещё лучше поступать так, как поступают СУБД - не удалять записи физически, а завести ещё одно поле, в котором хранить информацию о том, удалена запись или нет. Удалённые записи не показывать пользователю.
Serge_Bliznykov вне форума Ответить с цитированием
Старый 22.11.2013, 01:51   #3
3Doleg
Пользователь
 
Регистрация: 03.10.2012
Сообщений: 67
По умолчанию

Спасибо за ответ, 1 способ что вы написала как раз мне нужен!)
Если можно, поподробней опишите способ методом СУБД, буду благодарен)
3Doleg вне форума Ответить с цитированием
Старый 22.11.2013, 08:39   #4
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
Сообщение от 3Doleg Посмотреть сообщение
Спасибо за ответ, 1 способ что вы написала как раз мне нужен!)
пожалуйста!

Цитата:
Сообщение от 3Doleg Посмотреть сообщение
Если можно, поподробней опишите способ методом СУБД, буду благодарен)
дык, я уже выше попытался описать.
ну, значит так. у Вас есть структура (она же запись) - т.к. файл типизированный, то значит элементы его имеют определённую структуру (впрочем, конечно, файл может состоять и из элементов одного из стандартных типов (int, long, double и т.д.), но способ, о котором я говорю предполагает имеено использование структуры!)
в нашу структуру добавляем поле (ну, пусть это поле называется deleted):
Код:

struct  mytyperec   {
        char            name[21];
        long            value1;
        double         price;
....
       byte deleted;
};
разумеется, вместо типа byte (кстати, не знаю, есть ли такой тип в C ) можно использовать и любой другой подходящий тип (short, char).
Смысл в том, что если в этом поле находится значение ИСТИНА (это либо 1, либо, в случае char, какой-то символ, отличный от пробела) - значит, эта запись является УДАЛЁННОЙ! Эту запись не нужно отображать пользователю. Более того, когда добавляем новую запись в файл, можно её писать не в конец файла, а вместо удалённой записи. При необходимости, можно за один проход переписать в файл все записи, у которых нет пометки об удалении (в терминах СУБД такая операция называется "сжатие данных", например, PACK в dBase подобных языках).

преимущества использования отметки об удалении очевидны:
- чтобы удалить 2-ю запись в файле с 100000 записей (бывает и много больше) не придётся перезаписывать 99998 записей с места на место, при этом повышается надёжность (меньше шансов получить мусор вместо данных)
- запись может быть восстановлена в случае необходимости

недостаток - увеличение (на 1 байт на каждую запись) занимаемой памяти.


Теперь стало чуть-чуто понятнее?
Serge_Bliznykov вне форума Ответить с цитированием
Старый 22.11.2013, 11:41   #5
Bugrimov
C/C++, Java
Участник клуба
 
Аватар для Bugrimov
 
Регистрация: 28.03.2012
Сообщений: 1,679
По умолчанию

byte в Си нет!!!! а так вообще интересный способ... Спасибо!
"Keep it simple" - придерживайтесь простоты!
Уильям Оккам - "Не следует множить сущее без необходимости"
Сложность - враг простоты и удобства!
Bugrimov вне форума Ответить с цитированием
Старый 22.11.2013, 22:10   #6
3Doleg
Пользователь
 
Регистрация: 03.10.2012
Сообщений: 67
По умолчанию

Спасибо и да, стало чуть понятнее))
еще одна просьба если можно:
сама организация етого метода (тоесть алгоритм) можете подкинуть?
вот у меня такая структура:
Код:
struct Entrans
{
	char surName[15 + 1];	//фамилия
	char name[15 + 1];
	int dateBirth[3];          //масив из трез чисел(год.месяц.день)
	char zodiacSign[9 + 1];//знак зодиака
	char sex[8 + 1];          //пол
	char mail[50 + 1];	//адрес
}	part[100];                  //масив структур
допустим мне надо удалить фамилию, а если есть 2 таких фамилии, то делаем поиск по имени, ну и конечно если повтор имени - тогда по дате рождения(близницов таких думаю нет:D), ну я так написал удаления:
p.s.:по дате еще не успел зделать
Код:
void deleteRec()
{
	char sur[100], name[100];   //вводимая фамилия, имя(если нужно)
	int lenghtFile = 0, i, j, count = 0, index = 0, jndex = 0;  //счетчики цикла
	FILE *file;   //указатель на файл
	char tmpFile[1000][maxLenghtStr];   //буфер)

	printf("Введiти фамилию для удаления даных: ");
	scanf("%s", sur);
	strcat(sur, "\n");
	if((file = fopen(baseFile, "r")) == NULL)   //проверка на наличие файла
		errorFile();  //функция вывода ошибки, если нет файла
	while (!feof(file))  
		fgets(tmpFile[lenghtFile++], maxLenghtStr, file);   //считываем весь файл в буфер
	fclose(file);

	if((file = fopen(baseFile, "w")) == NULL)
		errorFile();
	for (i = 0; i < lenghtFile; i += 8)  //цикл += 8 потому что через кажных 8 строк в файле строка з фамилией
	{
		if (!strcmp(tmpFile[i], sur))  //дальше думаю не надо, так как сама суть есть выше
		{
			count++;

			if(count > 1)
			{
				printf("Є декілька записів з таким прізвищем, введіть потрібне ім'я: ");
				scanf("%s", name);
				for(index = 1; index < lenghtFile; index += 7)
					if(!strcmp(tmpFile[i], name))
					{
						for(jndex = -1; jndex < 7; jndex += 7)
							strcpy(tmpFile[index + jndex], "");
					}
			}
			if(count == 1)
			{
				for (j = 0; j < 8; j++)       //!!! вот тут сам процес удаления из файла, тоесть замена вместо записей пустотой
					strcpy(tmpFile[i + j], "");
			}
		}
	}

	for (i = 0; i < lenghtFile; i++)
		fprintf(file, "%s", tmpFile[i]);
	fclose(file);
	
	printTextFile();
	if (count > 0)
		printf("Знайдено записiв з таким прізвищем: %d\n", count);
	else
		printf("Записи з таким прізвищем не найденi!\n");

	system("pause");
}
Шаблон файла(что в нутри файла)
Код:
Мельник
Диана
1994
4
12
Рак
Ж
м.Суми,вул.Шевченка_21
Ковалева
Юлия
1994
7
2
Близнецы
Ж
м.Усинск,вул.Гагарина_100
Великов
Сергей
1995
5
14
Телец
Ч
м.Новий-Уренгой
Будет ли работать метод СУБД в моем случае?
Буду благодарен за ответ)
3Doleg вне форума Ответить с цитированием
Старый 22.11.2013, 23:09   #7
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
byte в Си нет
Зато там есть char.
Цитата:
Шаблон файла
Такая структура данных принципиальна?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 23.11.2013, 00:25   #8
3Doleg
Пользователь
 
Регистрация: 03.10.2012
Сообщений: 67
По умолчанию

просто так захотел сделать), думаю хорошо смотриться
3Doleg вне форума Ответить с цитированием
Старый 23.11.2013, 20:06   #9
Arhangel7
Пользователь
 
Регистрация: 27.02.2010
Сообщений: 90
По умолчанию

Я делаю так, читаю последнюю запись в файле, записываю её на место стираемой записи, затем обрезаю файл на одну запись. Способ с СУБД хорош только тогда, если планируется когда - либо востановить удаленную запись, в противном случае, разростание базы данных до колосальных размеров при малом колличестве полезных записей и увеличении времени на обработку самой базы (как итог).
Код:
int DellZap(void)/* 1-ok, 0-bad*/
{
  FILE *Baza;
  Opisanie_Zapchast zapchast;
  if (::nomZap==-1) return 0;
  if(0!=(Baza = fopen(::BazaName.c_str(),"r+b")))
  {
    fseek(Baza,-1*(sizeof(zapchast)),SEEK_END);
    fread(&zapchast,sizeof(zapchast),1,Baza);
    fseek(Baza,((nomZap-1)*sizeof(zapchast)),SEEK_SET);
    fwrite(&zapchast,sizeof(zapchast),1,Baza);
    fseek(Baza,-1*(sizeof(zapchast)),SEEK_END);
    chsize(fileno(Baza),ftell(Baza));
    fclose(Baza);
    ::nomZap==-1;
    return 1;
  }
  return 0;
}
как-то так

Последний раз редактировалось Arhangel7; 23.11.2013 в 20:09.
Arhangel7 вне форума Ответить с цитированием
Старый 23.11.2013, 21:20   #10
3Doleg
Пользователь
 
Регистрация: 03.10.2012
Сообщений: 67
По умолчанию

Интересный способ, большое спасибо)
Возможно у вас есть алгоритм ниже описаного удаления, буду благодарен если найдеться)
Цитата:
если нужно удалить K-ю запись, то можно в цикле переписать K+1 элемент на место K, K+2 на место K+1 и т.д. до последнего элемента массива.
Потом командой truncate обрезать файл по предпоследнюю запись включительно.
Всё.
3Doleg вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
неработает функция удаления из файла 3Doleg Общие вопросы C/C++ 0 05.11.2013 19:00
Способы удаления элемента массива в StringGrid dariya.95 Помощь студентам 23 28.06.2013 23:09
Способы изменения файла на сервере gufon Работа с сетью в Delphi 1 19.04.2011 10:47
Способы уменьшения исполняемого файла в Delphi 2010 STRELOK-2007 Общие вопросы Delphi 3 23.06.2010 12:23
Способы ведения файла-лога Norfolk Общие вопросы Delphi 2 14.06.2007 20:47