IPB
ЛогинПароль:

> Внимание!

1. Пользуйтесь тегами кода. - [code] ... [/code]
2. Точно указывайте язык, название и версию компилятора (интерпретатора).
3. Название темы должно быть информативным.
В описании темы указываем язык!!!

Наладить общение поможет, если вы подпишитесь по почте на новые темы в этом форуме.

 
 Ответить  Открыть новую тему 
> Проблема работы с файлами, С++ Builder
сообщение
Сообщение #1


Пионер
**

Группа: Пользователи
Сообщений: 103
Пол: Мужской
Реальное имя: Александр

Репутация: -  0  +


Доброй ночи, столкнулся с такой проблемой: при записи информации в файл, кроме нужной, в файл записывается еще всякая лишняя информация. Принып такой: если в файле уже есть запись с записываемым именем ее записывать не нужно, в файл записывается только новая запись. И еще такая ошибка, когда создаю файл, при чтении этого файла функция !feof(F) как-то неверно работает, а именно в цикл все равно заходит, но поидее не должно, т.к. файл пустой. Заранее благодарен за помощь.


Объявляется структура

struct YzelName
{
TCHAR name[10];
}yz;


Считывание данных из файла



AnsiString name;
NodeName = Edit1->Text;

bool flag_new_yzel = false;
char *File_Yzel_Name;

name = "Yzelname-" + ComboBox1->Items->Strings[ComboBox1->ItemIndex]; ///
File_Yzel_Name = name.c_str();

F = fopen(File_Yzel_Name,"ab+");
fclose(F);

F=fopen(File_Yzel_Name,"rb");
int i = 0;

while (!feof(F))
{
if (feof(F))
{
break;
}
fseek(F,i*sizeof(struct YzelName),SEEK_SET);
fread(&yz,sizeof(struct YzelName),1,F);
name = yz.name;
i++;
if (yz.name == NodeName)
{
flag_new_yzel = true;
}
else
{
flag_new_yzel = false;
}
}
fclose(F);


Запись в файл

if (flag_new_yzel == false)
{
F = fopen(File_Yzel_Name,"ab+");
perevod(yz.name,NodeName);
fwrite(&yz,sizeof(struct YzelName),1,F);
fclose(F);
}


Функция perevod

void perevod(TCHAR output_str[],AnsiString input_str)
{
int i;
char *str = input_str.c_str();
for (i = 0; i <= strlen(str); i++)
{
output_str[i] = str[i];
}
output_str[i-1] = '\0';
}


Сообщение отредактировано: ninja -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #2


Гость






Цитата
при чтении этого файла функция !feof(F) как-то неверно работает, а именно в цикл все равно заходит, но поидее не должно, т.к. файл пустой.
Правильно работает feof(), так как и должна. Дело в том, что эта функция не сигнализирует о том, что достигнут конец файла, а сигнализирует о том, что при чтении из файла пересечен маркер конца файла:

Цитата
int feof ( FILE * stream );

Check End-of-File indicator
Checks whether the End-of-File indicator associated with stream is set, returning a value different from zero if it is.
This indicator is generally set by a previous operation on the stream that reached the End-of-File.
Further operations on the stream once the End-of-File has been reached will fail until either rewind, fseek or fsetpos is successfully called to set the position indicator to a new value.
. То есть, до тех пор, пока какая-то операция (ну, в твоем случае - операция чтения) не попытается пересечь признак конца файла - feof() будет возвращать 0. Как только пересечет - индикатор будет установлен в 1, и следующий вызов feof() вернет уже ненулевое значение.

По теме - непонятно, зачем файлы, а не TStream-ы? И еще. Какая версия Билдера?
 К началу страницы 
+ Ответить 
сообщение
Сообщение #3


Пионер
**

Группа: Пользователи
Сообщений: 103
Пол: Мужской
Реальное имя: Александр

Репутация: -  0  +


Я со TStream никогда не работал, если честно, то даже не знаю что это, могу предположить что это поток данных. Владимир если не трудно приведите пожалуйста на моем примере, как работать с TStream, а версия Билдера 2010

Сообщение отредактировано: ninja -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #4


Гость






Хм. Нет, пожалуй не буду переделывать на Stream-ы, тут и с FILE-ом будет несложно. Сначала - код:


bool flag_new_yzel = false;

AnsiString FileName = "Yzelname-" + ComboBox1->Items->Strings[ComboBox1->ItemIndex]; ///

// Открываем файл на дозапись, если его не было - создастся
FILE *f = fopen(FileName.c_str(), "ab+");

int i = 0;
do
{
// А теперь - самое интересное. И при перемещении и при чтении
// из файла анализируем возвращаемые значения. Если хоть в одной
// из этих функций был сбой - то внутрь мы не попадаем, а сразу
// перейдем в конец цикла на проверку feof(). И она вернет "истину"...
if( (!fseek(f, i * sizeof(struct YzelName), SEEK_SET)) &&
(fread(&yz, sizeof(struct YzelName), 1, f) == 1) )
{
Name = yz.name;
flag_new_yzel = (Name == NodeName);
if(flag_new_yzel) break; // значение уже найдено - незачем ходить дальше
i++;
}
} while(!feof(f));

if(!flag_new_yzel)
{
perevod(yz.name, NodeName); // вот это я бы изменил...
fwrite(&yz, sizeof(struct YzelName), 1, f);
}
fclose(f);


Для начала - как бы я изменил perevod(). Очень просто: инициализировал бы все символы строки нулями, а потом копировал бы из строки все содержимое, до первого нуля, что ты сейчас и делаешь. Тогда в файле не оставались бы "хвосты" от более длинных строк, при последующей записи более коротких. Это ты для себя ставишь
output_str[i-1] = '\0';
, в файле-то эти "хвосты" все равно остаются. А зачем, если можно обойтись без этого?

Еще одно: у тебя Builder 2010, значит, очень многое будет зависеть от Юникодных настроек. А ты, по-моему, путаешься в типах String/AnsiString, и зачем-то еще TCHAR притянул. А ты в курсе, что в юникодном проекте у тебя TCHAR = wchar_t? Тогда почему передаешь в perevod() вторым параметром AnsiString? Головной боли не хватает? smile.gif Обращай на подобные вещи внимание.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #5


Пионер
**

Группа: Пользователи
Сообщений: 103
Пол: Мужской
Реальное имя: Александр

Репутация: -  0  +


Переделал структуру, получилось вот так:

struct YzelName
{
String name[10];
}yz;


Функция perevod()

void perevod(String *output_str, String input_str)
{
output_str[0] = input_str;
}


Добавлено через 5 мин.
Переделал структуру, получилось вот так:

struct YzelName
{
String name[10];
}yz;


Функция perevod()

void perevod(String *output_str, String input_str)
{
output_str[0] = input_str;
}


Но что-то в файл пишется непонятное, иероглифы всякие, а когда читаю данные, считывает что в файле хранится пустые строки.

Пробовал так

struct YzelName
{
TCHAR name[10];
}yz;


void perevod(char *output_str, String input_str)
{
for (int i = 0; i < strlen(output_str); i++)
{
output_str[i] = '\0';
} */
output_str = input_str.t_str();
}


Тоже работает неверно

Совсем что-то я запутался....

Сообщение отредактировано: ninja -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #6


Гость






Не-не-не... Это тебе не Паскаль, чтоб String name[10] выделяло место под строку из 10 символов. Это выделяется место под 10 указателей на класс String, с которым подобным образом вообще работать не рекомендуется.

Если тебя устраивает ,что твой код может быть только ANSI, то есть, на юникод ты его переносить не собираешься, то в настройках Билдера просто выстави, что TCHAR соответствует char-у, и оставь код как я привел. Иначе придется переделывать многое.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #7


Пионер
**

Группа: Пользователи
Сообщений: 103
Пол: Мужской
Реальное имя: Александр

Репутация: -  0  +


Все вроде работает!

У меня оказывается в настройках уже стояло соотношение TCHAR, char'y. Владимир, а что Вы имеете ввиду под

Цитата
Если тебя устраивает ,что твой код может быть только ANSI, то есть, на юникод ты его переносить не собираешься


Всмысле запускать программу на других компьютерах? или преобразовывать в другой тип? Запускать на других машинах придется, т.к. преподаватель будет проверять у себя.

P.S. Владимир спасибо Вам большое, как всегда выручаете !!!

Сообщение отредактировано: ninja -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #8


Гость






Запускать на других машинах можно по разному.

1 вариант: ты ничего в программе не меняешь, и твои программы работают ТОЛЬКО на машине с русскоязычной Windows (язык для non-Unicode приложений в системных настройках Control Panel -> Regional and Language Options -> вкладка Advanced установлен в Russian). Тогда все будет нормально.

2 вариант: машина с другими настройками на той же вкладке. У тебя проблемы, потому что ничего кириллического ты в файл уже не запишешь (вернее записать-то запишешь, только в виде вопросиков, а потом восстанавливать как?).

3 вариант: работа происходит только с латинскими символами - тогда тебе вообще без разницы, какие там настройки стоят у пользователя, работать будет в любом случае.
 К началу страницы 
+ Ответить 
сообщение
Сообщение #9


Пионер
**

Группа: Пользователи
Сообщений: 103
Пол: Мужской
Реальное имя: Александр

Репутация: -  0  +


ага понял, тогда буду записывать в файл информацию латинскими символами, еще раз Спасибо!
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #10


Пионер
**

Группа: Пользователи
Сообщений: 103
Пол: Мужской
Реальное имя: Александр

Репутация: -  0  +


Добрый вечер, не стал создавать новую тему написал тут. Снова проблема с файлами: когда записываю в файл следующую структуру:

struct pprName
{
TCHAR name[15];
int k;
int kolvo_sutok;
TCHAR data_provedeniya[11];
}yz;


Для преобразования использую функцию:

void perevod(TCHAR output_str[],AnsiString input_str)
{
int i;
char *str = input_str.c_str();
for (i = 0; i <= strlen(str); i++)
{
output_str[i] = str[i];
}
output_str[i-1] = '\0';
}


В массив yz.name записываю нулевой символ, но в файл попадает лишняя информация, когда считываю нужную запись, то выводится и нужная, и лишняя информация, как будто вместо 1й, записываются 2 записи. При чтении и записи данных в файл я использовал код который описан в предыдущих постах.
причем мне нужно чтобы переменная TCHAR name[15] была длинной больше чем 15 символов, но чем больше длинну я указываю в скобках, тем больше ненужной информации пишется в файл.

Заранее благодарен за помощь.

Сообщение отредактировано: ninja -
 Оффлайн  Профиль  PM 
 К началу страницы 
+ Ответить 
сообщение
Сообщение #11


Гость






Ты так и не делаешь того, что я написал выше:
Цитата("volvo")
Для начала - как бы я изменил perevod(). Очень просто: инициализировал бы все символы строки нулями, а потом копировал бы из строки все содержимое
То есть,
	memset(yz.name, 0, 15*sizeof(TCHAR)); // перед переводом - забиваешь все нулями
perevod(yz.name, s);

, теперь в самой функции perevod можно нулевой символ не копировать...
 К началу страницы 
+ Ответить 

 Ответить  Открыть новую тему 
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 





- Текстовая версия 19.03.2024 12:54
500Gb HDD, 6Gb RAM, 2 Cores, 7 EUR в месяц — такие хостинги правда бывают
Связь с администрацией: bu_gen в домене octagram.name