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

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

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

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

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

Ответ
 
Опции темы Поиск в этой теме
Старый 24.07.2015, 11:34   #1
Xo66um
Форумчанин
 
Регистрация: 11.05.2013
Сообщений: 154
По умолчанию Проблема с чтением файла (TFileStream)

Всем привет.

Пишу программу, которая должна уметь сохранять и читать данные из файла (обязательно через TFileStream), при этом часть данных представлена в виде двумерного динамического массива.

С сохранением проблем нет (вроде бы, хотя утверждать не берусь - одним WinHex-ом многое не расскажешь), проблема с чтением файла. В чем именно она заключается - я не знаю, и уже перепробовал буквально все.
Самое странное, что запись и чтение - два практически идентичных метода (различие только в Read/Write), поэтому у меня уже даже предположения закончились по поводу того, где может быть косяк.

Исходник программы прилагаю (он небольшой - лишь основной код, который вынес в отдельный проект, чтобы людям было проще по нему ориентироваться). Код оформлен.

В общем, я надеюсь на вашу помощь, потому как других вариантов у меня уже просто нет

P.S.
Delphi 7

Последний раз редактировалось Xo66um; 24.07.2015 в 20:39.
Xo66um вне форума Ответить с цитированием
Старый 24.07.2015, 11:44   #2
Vapaamies
Ваш К. О.
Участник клуба
 
Аватар для Vapaamies
 
Регистрация: 26.12.2012
Сообщений: 1,774
По умолчанию

Код:
TMatrix = array of array of PAnsiChar;
В таком виде TMatrix -- логически ошибочный тип. PChar -- это просто указатель, а данные по нему должны сохраняться программистом вручную: выделяться и освобождаться память, делаться корректное присваивание с копированием данных, FillChar и прочее.

Чтобы не морочиться, проще всего переделать на array of array of AnsiString и переписать соответствующим образом загрузку и сохранение файла.
Vapaamies вне форума Ответить с цитированием
Старый 24.07.2015, 11:44   #3
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Stream.Write(Matrix[X,Y], SizeOf(Matrix));
наводка - ну и какие значения в SizeOf(Matrix)?
почему использован PChar? пользуй string
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 24.07.2015, 12:06   #4
Xo66um
Форумчанин
 
Регистрация: 11.05.2013
Сообщений: 154
По умолчанию

Спасибо за быстрые ответы.

Честно говоря, что со String, что с PChar - ни так, и ни эдак - не работает, увы.
Память не выделял под PChar, да. Но я уверен, что выделение памяти в данном случае не требуется (или я ошибаюсь?).

Изначально использовался тип Char, но чтобы не мучиться с указателями - начал использовать PAnsiChar.

UPD:
Попробовал использовать все-таки тип String - ошибка сохранилась, также пробовал выделять и освобождать память (StrAlloc и StrDispose) - без толку.

Последний раз редактировалось Xo66um; 24.07.2015 в 12:32.
Xo66um вне форума Ответить с цитированием
Старый 24.07.2015, 12:36   #5
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Код:
TMatrix = array of array of String;
...
procedure Save(FileName:String;a:TMatrix);
var i,j,l:integer;
begin
 With TFileStream.Create(FileName,fmCreate) do begin
  l:=Length(a);  WriteInteger(l,sizeof(l));
  l:=Length(a[Low(a)]); WriteInteger(l,sizeof(l));
  for i:=Low(a) to High(a) do begin
   for j:=Low(a[i]) to High(a[i]) do begin
    l:=Length(a[i,j]); WriteInteger(l,sizeof(l));
    WriteBuffer(a[i,j][1],Length(a[i,j]));
   end;
  end;
  Free;
 end;
end;
...
procedure Load(FileName:String;var a:TMatrix);
var i,j,l,w:integer;
begin
 With TFileStream.Create(FileName,fmOpenRead) do begin
  ReadInteger(l,sizeof(l));
  readInteger(w,sizeof(w));
  SetLength(a,l,w);
  for i:=Low(a) to High(a) do begin
   for j:=Low(a[i]) to High(a[i]) do begin
    ReadInteger(l,sizeof(l));
    SetLength(a[i,j],l);
    ReadBuffer(a[i,j][1],l);
   end;
  end;
  Free;
 end;
end;
В качестве предложения по сериализации.
P.S. Не проверял.
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 24.07.2015, 12:53   #6
Xo66um
Форумчанин
 
Регистрация: 11.05.2013
Сообщений: 154
По умолчанию

Stilet, большое спасибо! Код рабочий
Правда, Delphi 7 не воспринимает WriteInteger и ReadInteger, поэтому пришлось подправить:

Код:
procedure Save(FileName: String; var a: TMatrix);
var
 i, j, l: integer;
 Stream: TFileStream;
begin
 Stream := TFileStream.Create(FileName,fmCreate);

 try
  l := Length(a);
  Stream.Write(l, SizeOf(l));

  l := Length(a[Low(a)]);
  Stream.Write(l,sizeof(l));

  for i := Low(a) to High(a) do
   begin
    for j := Low(a[i]) to High(a[i]) do
     begin
      l := Length(a[i,j]);
      Stream.Write(l, SizeOf(l));
      Stream.WriteBuffer(a[i,j][1], Length(a[i,j]));
     end;
   end;
 finally
  Stream.Free;
 end;
end;

procedure Load(FileName: String; var a: TMatrix);
var
 i, j, l, w: integer;
 Stream: TFileStream;
begin
 Stream := TFileStream.Create(FileName,fmOpenRead);

 try
  Stream.Read(l, SizeOf(l));
  Stream.Read(w, SizeOf(w));
  SetLength(a, l, w);

  for i := Low(a) to High(a) do
   begin
    for j := Low(a[i]) to High(a[i]) do
     begin
      Stream.Read(l, SizeOf(l));
      SetLength(a[i,j], l);
      Stream.ReadBuffer(a[i,j][1], l);
     end;
   end;
 finally
  Stream.Free;
 end;
end;
Может кому-то, кто также использует Delphi 7 - сгодится.

Но у меня два вопроса:
1. Возможна-ли поддержка юникода с типом string в Delphi 7?
2. Почему все-таки мой код чтения файла выбрасывает ошибку? Дело в неверной записи в файл, или что-то еще? Если так, то не могли-бы вы объяснить, в чем заключается ошибка?

P.S.
Обидно, но я почему-то не могу добавить плюс в репутацию - форум выдает сообщение (на скриншоте).

UPD:
Все, понял, в чем была ошибка... Спасибо еще раз всем, и особенно Stilet
Но вопрос по поводу юникода все еще неясен.
Изображения
Тип файла: jpg Ошибка.jpg (60.2 Кб, 170 просмотров)

Последний раз редактировалось Xo66um; 24.07.2015 в 13:04.
Xo66um вне форума Ответить с цитированием
Старый 24.07.2015, 13:12   #7
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Цитата:
Delphi 7 не воспринимает WriteInteger и ReadInteger
Ой ой... Вот чт значит "пересесть на Лазарус"... Основы начинаю забывать под давлением прогресса.
Цитата:
я почему-то не могу добавить плюс в репутацию - форум выдает сообщение
Это стандартная защита. Это в порядке вещей, не парься.
Цитата:
вопрос по поводу юникода все еще неясен.
Скорее нельзя, чем можно. Хотя могу ошибаться.
I'm learning to live...

Последний раз редактировалось Stilet; 24.07.2015 в 13:15.
Stilet вне форума Ответить с цитированием
Старый 24.07.2015, 13:22   #8
Xo66um
Форумчанин
 
Регистрация: 11.05.2013
Сообщений: 154
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
Скорее нельзя, чем можно. Хотя могу ошибаться.
Ну, даже если нет, то дальше я уже точно должен сам код модифицировать, а то как-то стыдно)

Цитата:
Сообщение от Stilet Посмотреть сообщение
Ой ой... Вот чт значит "пересесть на Лазарус"... Основы начинаю забывать под давлением прогресса.
На самом деле, такие мелочи не важны (как по мне), когда код рабочий) IDE все-равно подставляет имена методов по мере набора

Цитата:
Сообщение от Stilet Посмотреть сообщение
Это стандартная защита. Это в порядке вещей, не парься.
Понятно. Но все равно, спасибо вам большое, еще раз, от всей души, помогли
Xo66um вне форума Ответить с цитированием
Старый 24.07.2015, 13:55   #9
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

Пожалуйста )
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 25.07.2015, 20:15   #10
JUDAS
фонатик DELPHI
Форумчанин
 
Аватар для JUDAS
 
Регистрация: 14.01.2008
Сообщений: 714
По умолчанию

Цитата:
Проблема с чтением файла (TFileStream)
Мой любимый способ обмена информацией с диском =)))

-------------
ответы.
Как правильно подчеркнул Виталий (Stilet) самый удобный, безопасный и стопроцентный обмен данными в Делфи 7 через TFileStream, лучше организовывать посредством чтения/записи массива байтов.
Причём следует учитывать следующие особенности
1. PChar и все порождения от него (PAnsiChar, Pointer и.т.п) - для делфи это указатель на память размером 4 байт (тупой адрес). Поэтому, если используете информацию которая хранится в PCHar (например Вам прислала какая то Сишная Длл-ка) то следует организовать запись сначала 4 байт размер, потом тело.

Код:
  value : PChar;
  size  : integer;
begin
   size := StrLen(Value);
   stream.Write(size, sizeof(integer)); // пишем размер
   stream.Write(value^, size );   // пишем начинку
end;
чтение

Код:
  value : string;
  size  : integer;
begin
   stream.seek( смещение, откуда)
   stream.Read(size, sizeof(integer)); // читаем размер
   if size>0 then
   begin
     SetLength(value, size)
     stream.Write(value[1], size );   // читаем начинку
   end;
end;
2. string . Пишется и читается так же как и PChar но с учётом того, что используются другие функции
Код:
  value : string;
  size  : integer;
begin
   size := Length(Value);
   if size<>0 then
   begin 
     stream.Write(size, sizeof(integer)); // пишем размер  
     stream.Write(value[1], size );   // пишем начинку
   end;
end;
чтение то же что и в PChar

3. структуры. Структуры ВСЕГДА! нужно упаковывать перед записью, дабы не заниматься байтод...черством (вырваниваением полей в памяти) которым успешно занимаются Сишники перед подобными действиями.
Пример ниже пишется с packed
Код:
type
   MyType = packed record
      id : integer;
      name : array[0..12] of char;
      code : double;
      mask : array[0..2] of cyte;
  end;
4. массивы. Пишутся начиная с указателя на первый байт с указанием полного числа байт которые должны записаться на диск. массивы тоже желательно писать с размером в начале.

Код:
var   
   xxx : array of integer;
   size : integer;
begin
   SetLength(xxx, 13);
   .... заплняем массив значениями
   size = length(xxx)*sizeof(integer);
   stream.write(size, sizeof(integer));
   stream.write(xxx[0], size);
   Finalize(xxx);

end;
чтение

Код:
var   
   xxx : array of integer;
   size : integer;
begin
stream
   stream.seek( смещение, откуда)
   stream.read(size, sizeof(integer));
   if size<>0 then
   begin
      SetLength(xxx, size div sizeof(integer));
      stream.read(xxx[0], size);
   end;
   Finalize(xxx);
end;

5. WideString (Юникодовские строки). В отличии от строки и PChar Юникодовские строки пишутся/читаются как массив

Код:
procedure TForm1.Button1Click(Sender: TObject);
const
    s = 'У лукоморья дуб зелёный';
var Dest : array of char;
    Size : Integer;
    str  : TFileStream;
begin
  Size := Length(s)*2;
  SetLength(dest, size);

  StringToWideChar(s,PWideChar(Dest), size);

  str := TFileStream.Create('E:\dmp.txt', fmCreate);
  str.Write(size, sizeof(integer));
  str.Write(Dest[0], size);
  str.Free;

  Finalize(dest);
end;


procedure TForm1.Button2Click(Sender: TObject);
var Dest : array of char;
    Size : Integer;
    str  : TFileStream;
begin
  str := TFileStream.Create('E:\dmp.txt', fmOpenRead);
  str.Read(size, sizeof(integer));
  if Size>0 then
  begin
    SetLength(dest, size);
    str.Read(Dest[0], size);
  end;
  str.Free;

  Caption:= WideCharToString(PWideChar(Dest));

  Finalize(dest);
end;
во вложении "у лукоморья" на диске
Вложения
Тип файла: txt dmp.txt (50 байт, 140 просмотров)
95% сбоев и ошибок приложений, находится в полу метрах от монитора

Последний раз редактировалось JUDAS; 25.07.2015 в 20:18.
JUDAS вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Проблема с чтением файла. the27mart Общие вопросы C/C++ 4 18.11.2012 22:36
Проблема с чтением из типизированного файла BeCTHuK Паскаль, Turbo Pascal, PascalABC.NET 2 05.10.2011 20:57
проблема с чтением из файла salwator Помощь студентам 1 23.12.2010 12:11
Проблема с чтением из файла slamm PHP 12 16.01.2010 16:40
проблема с чтением из файла Tesmont Общие вопросы C/C++ 0 20.05.2009 19:39