Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Ошибка с динамическими массивами, И пролемы с чтением\записью в файл 
:(
    Опции темы
WaterProof
Дата 18.3.2007, 21:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


OverLapped



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 13.10.2006
Где: Москва

Репутация: нет
Всего: нет



Код

unit uLogin;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TfUser = class(TForm)
    GroupBox1: TGroupBox;
    Button1: TButton;
    Button2: TButton;
    edtPassw: TEdit;
    Userlist: TComboBox;
    Label1: TLabel;
    Label2: TLabel;
    Button3: TButton;
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
  TUser = record
   UserName:string[255];
   Password:string[255];
  end;
  TUsers = array of TUser;

var
  fUser: TfUser;
  Users:TUsers;

implementation

uses uMain;
{$R *.dfm}

procedure TfUser.Button3Click(Sender: TObject);
 var i:integer;
     f:file of TUsers;
     Maxusers:integer;
begin
assignFile(f, 'users.xdu');
reset(f);
read(f, Users);
CloseFile(F);
maxusers := length(users);



Application.ShowMainForm := true;
Close;
end;

end.



Delphi пишет, что "Type 'TUsers' needs finalization - not allowed in file type"(подсвечивается строка  в разделе var процедуры(f:file of TUsers;). Что это может быть?? Просто никогда не работал с динамическими массивами, да и сообщение вижу такое в первый раз...
PM MAIL ICQ   Вверх
skyboy
Дата 18.3.2007, 21:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


неОпытный
****


Профиль
Группа: Модератор
Сообщений: 9820
Регистрация: 18.5.2006
Где: Днепропетровск

Репутация: 4
Всего: 260



и как ты себе представляешь создание файла? размер динамического массива нефиксированный(а то потому бы он ещё "динамическим" звался?!), оттого программа не сможет получить доступ к 5(например) элементу - она не знает, где заканчивается 4-й, 3-й, 2-й и 1-й элементы. Если используешь структуру "file of"  длина одного элемента должна быть фиксированной. и никак иначе. а то(представь) просишь 100 элемент, а программа вынуждена анализировать предыдущие 99, чтоб выяснить, где этот сотый номер в файловой системе начинается. выход: 
  • работать с нетипизированными файлами
  • работать с текстовыми(единственный случай, когда квант чтения/записи - тип string/shortstring - не ограничен явно; зато там доступ только последовательный - прочитали строку, прочитали следующую, прочитали следующую и т.д. до конца файла или сброса)
  • хранить данные в БД(там можно и неопределенного размера класть - механизм чтения/записи под это "заточен")
  • переделать логику работы программы

PM MAIL   Вверх
Albinos_x
Дата 19.3.2007, 07:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Evil Skynet
****


Профиль
Группа: Комодератор
Сообщений: 3288
Регистрация: 28.5.2004
Где: X-6120400 Y-1 4624650

Репутация: 26
Всего: 108



вот набросал рабочий пример записи динамического массива на диск:
Код
...
type
   TFileSpeedRun = record       
       fsFileName  : String[255];
       fsGlyphFile : String[255];
       fsFontName  : String[50];
       fsFontSize  : Word;
       fsFontColor : TColor;
       fsFontStyle : Byte;
  end;
  TMasFileSpeedRun = array of TFileSpeedRun;

...
var
  Form1: TForm1;
  MasFileSpeedRun : TMasFileSpeedRun;
...
procedure TForm1.FormCreate(Sender: TObject);
var MFaleSpeedStream:TMemoryStream;
    Col,i:Integer;
    FileNameSet:String;
    SizeMem:Int64;
begin
// получаю путь к файлу
FileNameSet:=ExtractFilePath(Application.ExeName)+'Setting\SetFileSpiid.dat';
// проверяю его наличие
if FileExists(FileNameSet) then
   begin
   MFaleSpeedStream:=TMemoryStream.Create;
   try
   // загружаю  в память
   MFaleSpeedStream.LoadFromFile(FileNameSet);
   MFaleSpeedStream.Position:=0;
   SizeMem:=MFaleSpeedStream.Size;
   // гружу в массив
   for i:=0 to ((SizeMem div SizeOf(TFileSpeedRun))-1) do
      begin
      SetLength(MasFileSpeedRun,Length(MasFileSpeedRun)+1);
      MFaleSpeedStream.ReadBuffer(MasFileSpeedRun[i],SizeOf(TFileSpeedRun));
      end;
   finally
     MFaleSpeedStream.Free;
     end;
  // загружаю поле FileName в ListBox1
   Col:=Length(MasFileSpeedRun);
   for i:=0 to Col-1 do
      ListBox1.Items.Append(MasFileSpeedRun[i].fsFileName);
   end;
end;

procedure TForm1.SpeedButton10Click(Sender: TObject);
var MFaleSpeedStream:TMemoryStream;
    Col,i:Integer;
    FileNameSet:String;
begin
// получаю путь к фалу
FileNameSet:=ExtractFilePath(Application.ExeName)+'Setting\SetFileSpiid.dat';
// количество элементов в массиве
Col:=Length(MasFileSpeedRun);
// если 0, то ничего не сохраняю
if Col=0 then Exit;
MFaleSpeedStream:=TMemoryStream.Create;
try
MFaleSpeedStream.Position:=0;
// записываю массив в память
for i:=0 to (Col-1) do
   MFaleSpeedStream.WriteBuffer(MasFileSpeedRun[i],SizeOf(TFileSpeedRun));
// сохраняю в файл, т.к. в файле хранятся некоторые настройки необходимые для работы программы
// использую временный файл для записи, если при записи возникнут сбои, это не привёдёт к потере всех настроек
MFaleSpeedStream.SaveToFile(FileNameSet+'~');
finally
  MFaleSpeedStream.Free;
  end;
// удаляю старый файл
if DeleteFile(FileNameSet) then
   begin
   // если старый файл удалён, то переименовываю новый
   if not RenameFile(FileNameSet+'~', FileNameSet) then
      MessageDlg('Не удалось переименовать файл: '+#13#10+FileNameSet+'~'+#13#10+
                 'Для применения настроек переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
   end
   else
   MessageDlg('Не удалось удалить старый файл: '+#13#10+FileNameSet+#13#10+
              'Для применения настроек закройте программу, удалите указанный файл в ручную,'+
              #13#10+'переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
end;



--------------------
"Кто владеет информацией, тот владеет миром"    
Уинстон Черчилль
PM MAIL ICQ   Вверх
MetalFan
Дата 19.3.2007, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



Albinos_x, 
при загрузке:
1) какой смысл загружать весь файл в память в MemoryStream?
2) Зачем в цикле в каждой итерации перевыделять память? гораздо быстрее сделать это перед началом цикла. и вообще, зачем нужен цикл, если можно считать все одним махом? )
при сохранении:
1) "записываю массив в память"... абсолютно не нужная операция... а до этого массив где? не в памяти?

я бы переписал так:
Код

type
   TFileSpeedRun = packed record       //чтобы данные шли в памяти без выравнивания
       fsFileName  : String[255];
       fsGlyphFile : String[255];
       fsFontName  : String[50];
       fsFontSize  : Word;
       fsFontColor : TColor;
       fsFontStyle : Byte;
  end;
  TMasFileSpeedRun = array of TFileSpeedRun;

procedure TForm1.btn1Click(Sender: TObject);
var MFaleSpeedStream: TFileStream;
    Col,i:Integer;
    FileNameSet:String;
    SizeMem: Int64;
   ArrLength: Integer;
begin
  // получаю путь к файлу
  FileNameSet:=ExtractFilePath(Application.ExeName)+'Setting\SetFileSpiid.dat';
  // проверяю его наличие
  if FileExists(FileNameSet) then
  begin
    //открываем файл на чтение
    MFaleSpeedStream:=TFileStream.Create(FileNameSet, fmOpenRead);
    try
      SizeMem:=MFaleSpeedStream.Size;
      //определяем размер массива, чтобы в него поместилась инфа из файла
      ArrLength := SizeMem div SizeOf(TFileSpeedRun);
      SetLength( MasFileSpeedRun, ArrLength ); //выделяем память под массив
      MFaleSpeedStream.read( MasFileSpeedRun, SizeMem ); //читаем данные одним махом из файла
    finally
        MFaleSpeedStream.Free;
    end;
    // загружаю поле FileName в ListBox1
    Col:=Length(MasFileSpeedRun);
    for i:=0 to Col-1 do
      ListBox1.Items.Append(MasFileSpeedRun[i].fsFileName);
  end;
end;


procedure TForm1.btn2Click(Sender: TObject);
var
  MFaleSpeedStream: TFileStream;
  Col,i:Integer;
  FileNameSet:String;
begin
  // получаю путь к фалу
  FileNameSet:=ExtractFilePath(Application.ExeName)+'Setting\SetFileSpiid.dat';
  // количество элементов в массиве
  Col := Length(MasFileSpeedRun);
  // если 0, то ничего не сохраняю
  if Col=0 then Exit;
  MFaleSpeedStream:=TFileStream.Create( FileNameSet+'~', fmOpenWrite );
  try
     //записываем за один проход данные в файл.
     MFaleSpeedStream.Write( MasFileSpeedRun, Col * SizeOf(TFileSpeedRun) )
  finally
     MFaleSpeedStream.Free;
  end;
  // удаляю старый файл
  if DeleteFile(FileNameSet) then
     begin
     // если старый файл удалён, то переименовываю новый
     if not RenameFile(FileNameSet+'~', FileNameSet) then
        MessageDlg('Не удалось переименовать файл: '+#13#10+FileNameSet+'~'+#13#10+
                   'Для применения настроек переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
     end
     else
     MessageDlg('Не удалось удалить старый файл: '+#13#10+FileNameSet+#13#10+
                'Для применения настроек закройте программу, удалите указанный файл в ручную,'+
                #13#10+'переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
end;

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

с уважением.

Это сообщение отредактировал(а) MetalFan - 19.3.2007, 09:56


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
WaterProof
Дата 19.3.2007, 16:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


OverLapped



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 13.10.2006
Где: Москва

Репутация: нет
Всего: нет



Пока не получается - вылазит ошибка Access Violation:
Код

procedure TfUser.WriteUsers(Sender: TObject);
var
  MFaleSpeedStream: TFileStream;
  Col,i:Integer;
  FileNameSet:String;
begin
  // получаю путь к фалу
  FileNameSet:=ExtractFilePath(Application.ExeName)+'users\users.xda';
  // количество элементов в массиве
  Col := Length(Users);
  // если 0, то ничего не сохраняю
  if Col=0 then Exit;
  MFaleSpeedStream:=TFileStream.Create(FileNameSet+'~', fmOpenWrite);
  try
     //записываем за один проход данные в файл.
     MFaleSpeedStream.Write(Users, Col * SizeOf(TUser))
  finally
     MFaleSpeedStream.Free;
  end;
  // удаляю старый файл

  if DeleteFile(FileNameSet) then
     begin
     // если старый файл удалён, то переименовываю новый
     if not RenameFile(FileNameSet+'~', FileNameSet) then
        MessageDlg('Не удалось переименовать файл: '+#13#10+FileNameSet+'~'+#13#10+
                   'Для применения настроек переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
     end
     else
     MessageDlg('Не удалось удалить старый файл: '+#13#10+FileNameSet+#13#10+
                'Для применения настроек закройте программу, удалите указанный файл в ручную,'+
                #13#10+'переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
end;


1) постоянно выдает ошибку о том, что отсутствуеь файл, у которго тильда ~ в расширении
2)Access violation

Массив Users заполняю таким образом:

Код

procedure TfUser.Button1Click(Sender: TObject);
var username, password:string;
begin
 if InputQuery('Введите логин', 'Введите желаемое имя пользователя', username) then      //логин
  if InputQuery('Введите пароль', 'Введите пароль(запомните его обязательно!)', Password) then      //пароль
    begin
     SetLength(Users, Length(users)+1); // как кстати делать начальную длину массива?Может  быть поэтому получается ошибка??
      Users[length(Users)-1].UserName := username;
      Users[length(Users)-1].Password := MainForm.Crypt(password, PSWKey);
      WriteUsers(sender);
    end;
end;



Это сообщение отредактировал(а) WaterProof - 19.3.2007, 16:08
PM MAIL ICQ   Вверх
Rennigth
Дата 19.3.2007, 16:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 49
Всего: 76



Код

[quote=WaterProof, 19.3.2007,  16:07, post1069388]MFaleSpeedStream:=TFileStream.Create(FileNameSet+'~', fmOpenWrite or fmCreate);[/quote]




--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
WaterProof
Дата 19.3.2007, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


OverLapped



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 13.10.2006
Где: Москва

Репутация: нет
Всего: нет



Rennigth, одной проблемой меньше smile 
А вот с Access Violation что делать? Ошибка возникает явно не из-за отсутствия файла..... smile 
PM MAIL ICQ   Вверх
MetalFan
Дата 19.3.2007, 16:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



Цитата(WaterProof @  19.3.2007,  16:07 Найти цитируемый пост)
length(Users)-1

есть такая функция High(DynArr), что аналогично length(DynArr)-1 )

как описан тип TUser?



--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Rennigth
Дата 19.3.2007, 16:35 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 49
Всего: 76



Цитата(WaterProof @  19.3.2007,  16:24 Найти цитируемый пост)
А вот с Access Violation что делать?


где?

Добавлено @ 16:36 
MetalFan, посмотри первый пост


--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
MetalFan
Дата 19.3.2007, 16:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



Rennigth, а точно!
2WaterProof, добавь packed перед record в описании TUser


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
Rennigth
Дата 19.3.2007, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 49
Всего: 76



MetalFan, врятли из-за этого, там выравнивать нечего... хотя может уже структура другая. 

WaterProof, Но все равно добавь smile


--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
WaterProof
Дата 19.3.2007, 16:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


OverLapped



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 13.10.2006
Где: Москва

Репутация: нет
Всего: нет



Да в том то и дело, что я сразу добавил....
PM MAIL ICQ   Вверх
Rennigth
Дата 19.3.2007, 16:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1708
Регистрация: 21.6.2004
Где: Moscow

Репутация: 49
Всего: 76



На чем AV вылетает?

Добавлено @ 16:47 
И вообще давай весь код относящийся к сохранению.


--------------------
(* Honesta mors turpi vita potior *)
PM MAIL ICQ   Вверх
MetalFan
Дата 19.3.2007, 16:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 62
Всего: 128



е-мае! 
совсем забыл! тут же дин.массив!
передавай во write и read -  users[0], а не просто users


--------------------
There are always someone smarter than you...
PM MAIL   Вверх
WaterProof
Дата 19.3.2007, 17:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


OverLapped



Профиль
Группа: Участник
Сообщений: 44
Регистрация: 13.10.2006
Где: Москва

Репутация: нет
Всего: нет



Код

procedure TfUser.WriteUsers(Sender: TObject);
var
  MFaleSpeedStream: TFileStream;
  Col,i:Integer;
  FileNameSet:String;
begin
  // получаю путь к фалу
  FileNameSet:=ExtractFilePath(Application.ExeName)+'users\users.xda';
  // количество элементов в массиве
  Col := Length(Users);
  // если 0, то ничего не сохраняю
  if Col=0 then Exit;
  MFaleSpeedStream:=TFileStream.Create(FileNameSet+'~', fmOpenWrite or fmCreate);
  try
     //записываем за один проход данные в файл.
     MFaleSpeedStream.Write(Users[0], Col * SizeOf(TUser)) //<<<=====
  finally
     MFaleSpeedStream.Free;
  end;
  // удаляю старый файл

  if DeleteFile(FileNameSet) then
     begin
     // если старый файл удалён, то переименовываю новый
     if not RenameFile(FileNameSet+'~', FileNameSet) then
        MessageDlg('Не удалось переименовать файл: '+#13#10+FileNameSet+'~'+#13#10+
                   'Для применения настроек переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
     end
     else
     MessageDlg('Не удалось удалить старый файл: '+#13#10+FileNameSet+#13#10+
                'Для применения настроек закройте программу, удалите указанный файл в ручную,'+
                #13#10+'переименуйте файл SetFileSpiid.dat~ в SetFileSpiid.dat',mtError,[mbCancel],0);
end;


Так чтоли?? Чет под вечер мозга совсем не работает smile

Добавлено @ 17:08 
Да, и AV вылетает при применении процедуры WriteUsers....

Добавлено @ 17:09 
А где конкретно, не пишет... открывает почему dpr файл...
PM MAIL ICQ   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0599 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.