k_serg |
Отправлено: 18.05.2006, 13:40 |
|
Не зарегистрирован
|
помогите разобраться с записью/считыванием в файл
тип string после открытия файла оказывается пустым.
тип int — нормально.
изменения происходят , перед записью и после проверял все присутствует, при перезапуске программы оба string пусты.
при этом если поменять местами
string string_spisok_ystroistv[10];
unsigned int qqq_n;
в обьявлении то вообще проиходит ерунда.
Unit1.h
...
class TIssledov
{
public:
string string_spisok_ystroistv[10];
unsigned int qqq_n;
string str1;
unsigned int qqq_k;
};
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TMemo *Memo1;
TButton *Button1;
TButton *Button2;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
TIssledov Issledov;
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
Unit1.cpp
...
AnsiString put_dir;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
put_dir=GetCurrentDir();
//----считать-----
AnsiString File_Name_str = put_dir + AnsiString("\\")+ AnsiString("Issledov.dat");
int iFile = FileOpen(File_Name_str, fmOpenRead);
if(iFile==-1){ShowMessage("ошибка открытия файла Issledov.dat"); }
int err = FileRead(iFile,&Issledov, sizeof(TIssledov));
if( err==-1) {ShowMessage("невозможно прочитать данные Issledov.dat");FileClose(iFile);return; }
FileClose(iFile);
Memo1->Lines->Add(Issledov.str1.c_str());
for (int k=0;k<10;k++) {Memo1->Lines->Add(AnsiString((Issledov.string_spisok_ystroistv[k]).c_str())); }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
//------изменить-------
Issledov.qqq_n=1;
Issledov.str1="12345";
for (int k=0;k<10;k++) {Issledov.string_spisok_ystroistv[k]=(IntToStr(k)).c_str();}
Issledov.qqq_k=2;
Memo1->Lines->Add(Issledov.str1.c_str());
for (int k=0;k<10;k++) {Memo1->Lines->Add(AnsiString((Issledov.string_spisok_ystroistv[k]).c_str())); }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
//-----записать-----------
AnsiString File_Name_str = put_dir + AnsiString("\\")+ AnsiString("Issledov.dat");
int iFile = FileCreate(File_Name_str);
if(iFile==-1){ShowMessage("ошибка открытия файла Issledov.dat"); }
FileWrite(iFile,&Issledov, sizeof(TIssledov));
FileClose(iFile);
Memo1->Lines->Add(Issledov.str1.c_str());
for (int k=0;k<10;k++) {Memo1->Lines->Add(AnsiString((Issledov.string_spisok_ystroistv[k]).c_str())); }
}
//---------------------------------------------------------------------------
|
|
Guest |
Отправлено: 18.05.2006, 14:17 |
|
Не зарегистрирован
|
Грубо говоря string это указатель на массив char. Поэтому для загрузки в string (при строках переменной длины и динамическом выделении памяти) надо
- узнать какова будет длина строки
- запросить под неё память (не забыть о EOS, но это как хранятся данные)
- в классе полю присвоить этот string
- прочитать в эту память байты из файла
PS.
Чтение(запись) экземпляра класса из(в) файл более логично сделать методом класса TIssledov |
|
Konstantine |
Отправлено: 19.05.2006, 21:45 |
|
Мастер участка
Группа: Модератор
Сообщений: 545
|
если файл текстовый — проще использовать класс TStringList
если бинарный — то через TMemoryStream
|
|
exp |
Отправлено: 26.05.2006, 22:15 |
|
Мастер участка
Группа: Участник
Сообщений: 304
|
Если работаешь апишными функциями — то вот для сохранения строки придется попотеть о посимвольно сохранять строку (метод SaveStr(string Str))
CODE |
class TIssledov
{
public:
string string_spisok_ystroistv[10];
unsigned int qqq_n;
string str1;
unsigned int qqq_k;
//----Полезные методы--------
void SaveStr(string FileName,string Str)
{
int hFile = 0;
if(!FileExists(FileName)) hFile = FileCreate(FileName);
else hFile = FileOpen(FileName,fmOpenWrite);
if(!hFile) return;
int Length = Str.size(); // насколько помню, такой метод есть
FileWrite(hFile,(char*)&Length,sizeof(Length)); // сохраняем длину строки, потому что нам еще загружать её
for(int i = 0; i < Length; i++) //Сохраняем посимвольно строку.
FileWrite(hFile,(char*)&Temp[i+1],sizeof(char));
}
void LoadStr(string FileName,string &Str)
{
int hFile;
if(FileExists(FileName))
{
hFile = FileOpen(FileName, fmOpenRead);
int Length;
FileRead(hFile,(char*)&Length,sizeof(Length)); // читаем кол-во символов
string StrLoaded = "";
for(int i = 0; i <Length; i++) // посимвольно читаем
{
FileRead(hFile,&C,sizeof(char));
StrLoaded += C;
}
}
}
// Сохранение объекта в файл
void Save(string FileName)
{
// мне лень писать открытие файла. сам сделаешь
for(int i = 0; i <10; i++) SaveStr(FileName,string_spisok_ystroistv[i]);
// Дальше мне тоже лень. дальше просто числа сохранить.
}
};
|
Надеюсь, основная мысль понятна . Ты сохранял не строку а указатель. После загрузки по адресу, который ты сохранил, совершенно не обязательно должна находиться твоя строка . Функции FileRead и FileWrite используют параметром размер буфера чтения. Ты туда подсовываешь sizeof(TIssledov), который, кстати, не меняется в зависимости от длины строк твоего string_spisok_ystroistv[10].
Выправляй код. Удачи в отладке .
|
|
Grigoriy |
Отправлено: 27.05.2006, 00:56 |
|
Мастер участка
Группа: Участник
Сообщений: 381
|
QUOTE | Если работаешь апишными функциями — то вот для сохранения строки придется попотеть о посимвольно сохранять строку (метод SaveStr(string Str)) |
Да никакого подобного ограничения в API-функциях для работы с файлами нет.
А учёт регистра символов в идентификаторах... ?
FileWrite
FileRead
это вовсе не АПИ, а стандартные функции языка Builder.
QUOTE |
CODE |
if(!FileExists(FileName)) hFile = FileCreate(FileName);
else hFile = FileOpen(FileName,fmOpenWrite);
|
|
Ну, хорошо, а где же мы закрываем файл ?
QUOTE | int Length = Str.size(); // насколько помню, такой метод есть |
Да нету такого метода.
QUOTE |
Функции FileRead и FileWrite используют параметром размер буфера чтения. Ты туда подсовываешь sizeof(TIssledov), который, кстати, не меняется в зависимости от длины строк твоего string_spisok_ystroistv[10].
|
Ну и какой смысл, что он запишет в файл поля объекта TIssledov.
Строки
CODE |
public
//------------
string string_spisok_ystroistv[10];
//------------
string str1;
//------------------
|
не сохранятся же в таком случае !
QUOTE |
CODE |
for(int i = 0; i <10; i++) SaveStr(FileName,string_spisok_ystroistv[i]);
|
|
Так что же делает этот цикл ?
Он просто пишет на одно и то же место в файле с именем FileName разные строки ?
Знаете почему ?
Смотрите...
Вы открываете файл. Указатель файла после открытия устанавливается в начало файла, а не в конец. И начинаем перезаписывать начало файла каждый раз снова. Мы просто затираем старую строку новой и всЁ.
Там же надо перемещать указатель файла в конец файла.
Тогда непонятен смысл функции чтения строки -
LoadStr
Функция может читать только первую строку.
Ну, да ладно.
Вот мой код.
АПИ чистые.
CODE |
//********************************************************
int SaveStr(AnsiString FileName,AnsiString Str)
{
unsigned long* NumberOfBytesWritten=new unsigned long;
void* hFile = 0;
void* p;
int* L=new int;
if (
!(hFile=CreateFile(FileName.c_str(),GENERIC_WRITE,0,0,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0)))
return -1;
SetFilePointer(hFile,0,0,FILE_END);
p=Str.c_str();
*L=Str.Length();
WriteFile(hFile,L,4,NumberOfBytesWritten,0);
WriteFile(hFile,p,*L,NumberOfBytesWritten,0);
CloseHandle(hFile);
delete L;
delete NumberOfBytesWritten;
return 0;
};
//********************************************************
int LoadStr(AnsiString FileName,AnsiString &Str)
{
unsigned long* lpNumberOfBytesRead=new unsigned long;
void* hFile = 0;
void* p;
int* L=new int;
if (
!(hFile=CreateFile(FileName.c_str(),GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0)))
return -1;
ReadFile(hFile,L,4,lpNumberOfBytesRead,0);
Str.SetLength(*L);
p=Str.c_str();
ReadFile(hFile,p,*L,lpNumberOfBytesRead,0);
CloseHandle(hFile);
if (*lpNumberOfBytesRead != *L) return -1;
delete L;
delete lpNumberOfBytesRead;
return 0;
};
//********************************************************
|
И пример его использования
CODE |
void __fastcall TForm1::Button1Click(TObject *Sender)
{
AnsiString ffr;
ffr=Edit1->Text;
SaveStr("C:\\fffdsdcsdsdf.fwr",ffr);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
AnsiString ffr1;
LoadStr("C:\\fffdsdcsdsdf.fwr",ffr1);
Edit2->Text=ffr1;
}
|
Но у меня тоже LoadStr читает только первую строку.
Мне лень самому ...
Отредактировано Grigoriy — 27/05/2006, 01:31
|
|
** exp |
Отправлено: 27.05.2006, 16:02 |
|
Не зарегистрирован
|
Какой блистательный разнос ты мне устроил!!! Я упал со стула и лежу в нокауте. Как оказалось, я вааааааще не знаю как работать с файлами.
Ести ты, Grigory, не заметил, то автор темы и сам знает когда надо закрывать файлы, единственное, что ему надо было — строки сохранять. Вот я и написал ему, идею, как сохранить строку, но твой код, конечно, круче! Я даже уверен, что k_serg даже им воспользуется. Ведь ты файлы закрываешь, в отличие от меня.
QUOTE |
Ну и какой смысл, что он запишет в файл поля объекта TIssledov.
Строки
CODE
public
//------------
string string_spisok_ystroistv[10];
//------------
string str1;
//------------------
не сохранятся же в таком случае !
|
Гениально! ты понял, что я хотел сказать! Чудеса проницательности!
QUOTE |
Он просто пишет на одно и то же место в файле с именем FileName разные строки ?
Знаете почему ?
Смотрите...
Вы открываете файл. Указатель файла после открытия устанавливается в начало файла, а не в конец. И начинаем перезаписывать начало файла каждый раз снова. Мы просто затираем старую строку новой и всЁ.
Там же надо перемещать указатель файла в конец файла.
|
Да ты что!!!!? А я-то думал.....
Знаешь, я пришёл с работы оооочень уставший. И мне не хотелось выковыривать всех жуков из того кода, который я написал. Ты, смотрю, тоже под конец задолбался, раз самому лень.
Ну а за АПИ, ты уж прости меня. Я заблуждался. |
|
Grigoriy |
Отправлено: 27.05.2006, 16:28 |
|
Мастер участка
Группа: Участник
Сообщений: 381
|
QUOTE | Я упал со стула и лежу в нокауте. |
Ну-ну.
Только падать не надо. Могут быть плохие последствия, а хорошего ничего...
QUOTE | Как оказалось, я вааааааще не знаю как работать с файлами.
|
Ну никто из нас с рождения не знает как работать с файлами.
QUOTE | Я даже уверен, что k_serg даже им воспользуется. |
И более того — усовершенствует...
|
|
Mapcuk |
Отправлено: 09.06.2006, 09:29 |
|
Не зарегистрирован
|
#include // она получше будет причём вкючает и iostream
void main()
{...
string IFile,OFile;
cout<<"Vvedite imya vhodnogo i vyhodnogo failov: ";
cin>>IFile>>OFile; // имена файлов
ifstream infile ( IFile.c_str() ); создаём объект откуда будем читать
ofstream outfile ( OFile.c_str() );
if ( ! outfile ) // false, если файл не открыт
cout << "Oshibka otkrytiya faila-vyvoda.\n";
if ( ! infile ) // false, если файл не открыт
cout << "Oshibka otkrytiya faila-vvoda.\n";
string buffer;
while ( infile>> buffer ) // читать из файла по словам по не кончаться
cout << buffer << "\n" ; // причём считывает слово до пробела табуляции
}
или конца строки и конца файла
тока string и AnsiString не особо совместимы
|
|
Mapcuk |
Отправлено: 09.06.2006, 09:31 |
|
Не зарегистрирован
|
в начале забыл указать
#include |
|
Shagg |
Отправлено: 09.06.2006, 12:42 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 69
|
тож мне апишники млин... если помните d С++ определены операции смещения "<<" и ">>", которые перегружены для потоковых классов(istream,ostream, fstream...) как операции чтения/записи.
То бишь их можно использовать так:
CODE |
#include <fstream>
#include <string>
using namespace std;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
ofstream f("c:\t.txt", ios::out);
string s;
s = "adsadasd";
f<<s;
f.close();
}
//---------------------------------------------------------------------------
|
А еще, кстати, существуют манипуляторы, используя которые можно выводить отформатированный текст. Для того чтоб использовать их нуна подключить файл iomanip...
хотя нет API это круто,надо на апи писать — дядя Билли так сказал. |
|
Gedeon |
Отправлено: 13.06.2006, 11:42 |
|
Ветеран
Группа: Модератор
Сообщений: 1742
|
QUOTE (Shagg @ 09/06/2006, 12:42) | хотя нет API это круто,надо на апи писать — дядя Билли так сказал. |
Смотря что и под что писать!
|
|
Shagg |
Отправлено: 13.06.2006, 14:08 |
|
Дежурный стрелочник
Группа: Участник
Сообщений: 69
|
QUOTE (Gedeon @ 13/06/2006, 11:42) | Смотря что и под что писать! |
Я не спорю, но, по моему, для того, чтобы записать пару строк в файл не обязательно создавать проекцию файла и ловить системные привелегии.
под что писать? встроенные функции с++ работают на большинстве поатформ, а апи только под окнами |
|
|