Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  02:36[Войти] | [Зарегистрироваться]
Ответ на вопрос № 72821

Вопросы с аналогичными сообщениями об ошибках:
  • Access violation at address ... (776)

    12-09-2009 02:48
    Здравствуйте уважаемые жители Королевства.

    При попытке чтения отображенный в память файл, возникает ошибка: "Access violation at address 0040B$E6 in module ‘Project1.exe’. Read of address 003D0000".

    Ошибка возникает не всегда. Где-то 5-7 раз из десяти запусков программы. То есть иногда программа работает без ошибок, а при следующем запуске может вылететь ошибка. Закономерностей ошибки никаких не заметил.

    Код.

    procedure TForm1.Button1Click(Sender: TObject);
    var
      str:string;
      FFileHandle: THandle; // Дескриптор открытого файла
      FMapHandle: THandle;  // Дескриптор объекта отображения файла
      FData: PByte;        // Указатель на данные файла при отображении
      PData: PChar;        // Указатель для ссылки на данные файла
      ViewPos:Int64;        // Cмещение файла, откуда начинается его отображение
      ViewSize:DWORD;      // Определяет количество байтов файла,
                            // предназначенных для отображения.
                            // Нулевое значение указывает на отображение целого файла


    begin
      ViewPos:=65536;
      ViewSize:=65536;
      getMem(PData,20);

      // Открытие файла, кодировка UTF-16LE
      FFileHandle := FileOpen('1.txt', fmOpenRead);
      // Создание объекта отображения в память
      FMapHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil);
      // Отображение данных файла в адресное пространство процесса
      FData:=MapViewOfFile(FMapHandle,FILE_MAP_READ,
      Int64Rec(ViewPos).Hi, Int64Rec(ViewPos).Lo, ViewSize);

      //ошибка, если она есть, происходит на этой строке
      StrLCopy( PData, PChar(FData), 10);

      str:=PData;
      memo1.Lines.Add(str);

      FreeMem(PData);
      CloseHandle(FFileHandle);
      UnmapViewOfFile(FData);

    end;



    Использую Delphi 2009. Если заменить переменную ViewSize на ноль, тогда ошибка пропадает. 

    Что я делаю не так? В какую сторону глядеть и копать? Посоветуйте что-нибудь.

    [+] Добавить в избранные вопросы

    Отслеживать ответы на этот вопрос по RSS

    Ответы:


    Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
    Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

    16-09-2009 02:34 | Сообщение от автора вопроса
    А можно полюбопытствовать, каким образом вы её решили?
    Будут в файлах: #0

    15-09-2009 02:10 | Комментарий к предыдущим ответам
    "xxx: Попробую и обязательно отпишусь" - самое популярное последнее сообщение в топиках :D

    14-09-2009 09:17 | Вопрос к автору: запрос дополнительной информации
    Ошибка больше не вылазит, и это главное
    А можно полюбопытствовать, каким образом вы её решили?

    14-09-2009 08:53
    То есть, в середине вашего текста может быть нулевой символ?!
    Не знаю пока еще, подумаю. Ошибка больше не вылазит, и это главное, остальное решится так или иначе.

    14-09-2009 03:50 | Комментарий к предыдущим ответам
    Я писал:
    А если... вместо:
    getMem(PData,ViewSize);
    вот так:
    getMem(PData,ViewSize+1 {2?});

    И забыл дописать: добавьте к концу #0.

    Если в этом окне есть где-нибудь ближе к концу завершающий ноль - #0
    То есть, в середине вашего текста может быть нулевой символ?!

    14-09-2009 03:42 | Сообщение от автора вопроса
    Всем спасибо. Причина ошибки известна, проблема, вероятно, будет тоже решена.
    Александр Алексеев, совершенно правильно сказал про ноль.

    Эта функция создает окно, в котором представлен объект отображения файла:

      pView:=MapViewOfFile(FMapHandle, FILE_MAP_READ,
      Int64Rec(ViewPos).Hi, Int64Rec(ViewPos).Lo, ViewSize);


    Если в этом окне есть где-нибудь ближе к концу завершающий ноль - #0, то и ошибки в следующей строке нет:

    StrLCopy( PData, PChar(pView), 10);



    14-09-2009 00:52 | Комментарий к предыдущим ответам
    А если... вместо:
    getMem(PData,ViewSize);
    вот так:
    getMem(PData,ViewSize+1 {2?});

    13-09-2009 11:12
    Вот это:


    ...
    getMem(PData,20);
    ...
    StrLCopy( PData, PChar(pView), 10);
    ...

    меняем на это:

    ...
      if FileSize > BlockSize then ViewSize:=BlockSize
      else ViewSize:=FileSize;

      getMem(PData,ViewSize);
    ...
      StrLCopy(PData, PChar(pView), ViewSize);
    ...


    Сейчас собрал проект на Delphi 2010 (под WinXP SP2), потестировал, ошибок не возникло.

    Проверьте ещё без этих строк:

        StrLCopy( PData, PChar(pView), 10);
        str:=PData;
        memo1.Lines.Add(str);


    К слову, в Delphi 2009 и 2010, PChar равен PWideChar, а не PAnsiChar.

    13-09-2009 09:54 | Сообщение от автора вопроса
    Сейчас откомпилоровал в Delphi 7, работает без ошибок во всех операционных системах. Поставил еще Delphi 2010, к сожелению, то же самое, что и D2009. А мне бы хотелось, чтоб работало именно в 2009 или 2010.

    >>>Вообще-то, ошибка вылетает тут: str:=PData;

    Нет. У меня, там, где я отметил. Например, если написать так, то ошибка не исчезнет:

      //str:=PData;
        str:='раз два';



    А если так:

      try
        StrLCopy( PData, PChar(pView), 10);
      except
      ShowMessage('Ошибка именно здесь!');
      end;


    То появится этот мессидж.

    За ссылки спасибо, почитаю.

    13-09-2009 08:10
    Вообще-то, ошибка вылетает тут:

    str:=PData;



    Кто вам сказал, что 10 символов, что вы скопировали в PData из файла, обязательно заканчиваются нулём?

    Ссылки для чтения: раз и два

    13-09-2009 07:14 | Сообщение от автора вопроса
    >>>А в этом тестовом приложении, ваша ошибка точно появляется? Попробовал на нескольких файлах, у меня ошибок нет.undefined

    У меня ОС – Windows 7, 64-бит. Сейчас попробовал запустить программу на виртуальной машине. На русской 32-битной XP ошибок нет. На английской XP и на русской win2000 - не запустилось ни разу (может мало пробовал). На русской 32-битной Vista тоже запустилось, но с 11 попытки… Мне надо, чтоб работало везде, ну разве что кроме w98. Также пробовал с другими файлами, кодировками. Результат тот же.

    >>>А каков среднестатистический размер читаемого файла?undefined
    Средний размер 20 Мб. Но есть и больше, самый большой сейчас 420 Мб. Файлов около 50.

    >>>А позиция этого куска, кратна dwAllocationGranularity?undefined
    С этим не будет проблемы.

    >>>Добавте ShowMessage(SysErrorMessage(GetLastError)) после строки, где возникает ошибка.undefined

    Добавил, при ошибке ничего не пишет. Если добавлять строку не сразу, а после finally,  пишет, что операция успешна завершена, потом появляется привычное сообщение с ошибкой: Access violation итд.

    try
        //ошибка, если она есть, происходит на этой строке
        StrLCopy( PData, PChar(pView), 10);
      finally
        ShowMessage(SysErrorMessage(GetLastError));



    13-09-2009 05:10 | Вопрос к автору: запрос дополнительной информации
    Так это тестовое приложение будет наиболее походить на рабочий проект.

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

    А в этом тестовом приложении, ваша ошибка точно появляется? Попробовал на нескольких файлах, у меня ошибок нет.

    Программе необходимо очень быстро прочитать кусок большого файла
    А каков среднестатистический размер читаемого файла?

    Предполагается, что программа знает, где этот кусок находится
    А позиция этого куска, кратна dwAllocationGranularity?

    Добавте ShowMessage(SysErrorMessage(GetLastError)) после строки, где возникает ошибка.

    12-09-2009 23:25 | Сообщение от автора вопроса
    Попробовал изменить код, с теми поправками, что вы внесли. К сожалению, ошибка некуда не пропала:

    procedure TForm1.Button1Click(Sender: TObject);
    var
      SysInfo: TSystemInfo;
      BlockSize, FileSize: Int64;
      str:string;
      FFileHandle: THandle; // Дескриптор открытого файла
      FMapHandle: THandle;  // Дескриптор объекта отображения файла
      pView: Pointer;      // Указатель на данные файла при отображении
      PData: PChar;        // Указатель для ссылки на данные файла
      ViewPos:Int64;        // Cмещение файла, откуда начинается его отображение
      ViewSize:DWORD;      // Определяет количество байтов файла,
                            // предназначенных для отображения.
                            // Нулевое значение указывает на отображение целого файла


    begin

      GetSystemInfo(SysInfo);
      BlockSize:=SysInfo.dwAllocationGranularity * 1;

      //ViewPos:=65536;
      //ViewSize:=65536;
      getMem(PData,20);

      // Открытие файла, кодировка UTF-16LE
      FFileHandle := FileOpen('1.txt', fmOpenRead);
      if FFileHandle=0 then ShowMessage('Ошибка открытия файла');


      // Создание объекта отображения в память
      FMapHandle := CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil);
      if FMapHandle=0 then ShowMessage('Объект отображения не создан');


      Int64Rec(FileSize).Lo:=GetFileSize(FFileHandle, @Int64Rec(FileSize).Hi);
      ViewPos:=0;

      if FileSize > BlockSize then ViewSize:=BlockSize
      else ViewSize:=FileSize;

      pView:=MapViewOfFile(FMapHandle, FILE_MAP_READ,
      Int64Rec(ViewPos).Hi, Int64Rec(ViewPos).Lo, ViewSize);
      if pView=nil then ShowMessage('ошибка отображения данных');;

      try
        //ошибка, если она есть, происходит на этой строке
        StrLCopy( PData, PChar(pView), 10);
        str:=PData;
        memo1.Lines.Add(str);

      finally
        CloseHandle(FFileHandle);
        FreeMem(PData);
        UnmapViewOfFile(pView);
      end;

    end;



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

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

    12-09-2009 18:28
    Во первых, у вас неправильно реализовано смещение (если оно там вообще должно быть). Позиция (ViewPos) в файле, с которой вы начинаете проецирование, изначально равна 64 кб, получается первые 64 кб вы не задумываясь пропускаете. Далее вы устанавливаете размер (ViewSize) проецируемого файла в 64 кб и при этом не проверяете размер самого файла, когда он оказывается меньше 64 кб - вы получаете свой заслуженный "Access Violation".

    Во вторых, процедуру проецирования файла, вы выполняете только один раз, получается читаете только первые (вторые) 64 кб (по крайней мере, while'ов или repeat'ов не видно).

    В третьих, не стоит пренебрегать проверками на ошибки, обязательно проверяйте значения возвращаемые функциями, да и про try..finally не забывайте.

    Ну и в четвёртых, зачем всё это вам? Я сильно сомневаюсь, что вы работаете с текстовыми файлами (пусть даже в юникоде), размер которых превышает 2 Гб. Чем вас не устраивает обычное чтение файла? Тем более, для небольших файлов, по скорости не уступает маппированию.


    Ладно, решать вам.
    По поводу кода, если вы всё-таки читаете (думаете, что читаете) файл целиком - удалите из кода ViewPos и ViewSize, и уберите смещение - MapViewOfFile(FMapHandle,FILE_MAP_READ, 0, 0, 0).

    Если же вам действительно жизненно необходимо чтение блоками, то вот:

    procedure TForm1.Button2Click(Sender: TObject);
    var
    SysInfo: TSystemInfo;
    pView: Pointer;
    FMapHandle, FFileHandle: THandle;
    ViewPos, ViewSize, FileSize, BlockSize: Int64;
    begin
    GetSystemInfo(SysInfo);
    BlockSize:=SysInfo.dwAllocationGranularity * 1; //вместо "1", указываем минимальный блок чтения (смещение), который должен быть кратен гранулярности памяти (обычно 64 Кб)

    FFileHandle:=FileOpen('C:\Temp\123.txt', fmOpenRead);
    if FFileHandle=0 then
    Exit;

      try
    FMapHandle:=CreateFileMapping(FFileHandle, nil, PAGE_READONLY, 0, 0, nil);
    if FMapHandle=0 then
    Exit;

        try
      if GetLastError<>0 then
      Exit;

      Int64Rec(FileSize).Lo:=GetFileSize(FFileHandle, @Int64Rec(FileSize).Hi);
      ViewPos:=0;

        repeat
      if FileSize>BlockSize then
      ViewSize:=BlockSize
        else
      ViewSize:=FileSize;

      pView:=MapViewOfFile(FMapHandle, FILE_MAP_READ, Int64Rec(ViewPos).Hi, Int64Rec(ViewPos).Lo, ViewSize);
      if pView=nil then
      Exit;

          try
        Inc(ViewPos, ViewSize);
        Dec(FileSize, ViewSize);

        //ваши действия...

          finally
        UnmapViewOfFile(pView);
          end;

        until FileSize=0;


        finally
      CloseHandle(FMapHandle);
        end;

      finally
    CloseHandle(FFileHandle);
      end;
    end;


    Добавьте свое cообщение

    Вашe имя:  [Войти]
    Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
    контрольный вопрос:
    Жил-был у бабушки серенький КТО?
    в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
    Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
    Тип сообщения:
    Текст:
    Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Вопросы с аналогичными сообщениями об ошибках:
  • Access violation at address ... (776)


    Страница избранных вопросов Круглого стола.
  •   
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования