При работе с файлами в среде Delphi иногда возникают проблемы, связанные с настройками буферизации. Одной из таких проблем является ошибка EWriteError с сообщением "stream read error", которая появляется при использовании флагов FILE_FLAG_WRITE_THROUGH и FILE_FLAG_NO_BUFFERING. В данной статье мы рассмотрим, почему это происходит, и предложим решение проблемы.
Проблема с буферизацией
При использовании флага FILE_FLAG_NO_BUFFERING операционная система не буферизует данные, что означает, что каждое записанное в файл значение будет немедленно записано на диск. Это может быть полезно для определенных приложений, например, для обеспечения атомарности операций записи.
Однако, при использовании данного флага, код на Delphi возвращает ошибку EWriteError с сообщением о "stream read error". Пример кода, вызывающего данную ошибку, выглядит следующим образом:
procedure TForm1.btn1Click(Sender: TObject);
var
fsFSArquivoAAC: TFileStream;
L, lastErr: Cardinal;
R: WideString;
hn: THandle;
begin
hn := Windows.CreateFile(PChar('TesteAAC.AAC2'),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_WRITE_THROUGH or FILE_FLAG_NO_BUFFERING, 0);
// Проверка результата вызова CreateFile
// ...
fsFSArquivoAAC := TFileStream.Create(hn);
try
R := 'BatatinhaquandoNasceEspalharamapelochao';
// Запись строки в файл
L := Length(R);
fsFSArquivoAAC.WriteBuffer(L, SizeOf(Integer));
if L > 0 then
fsFSArquivoAAC.WriteBuffer(R[1], L * SizeOf(WideChar));
finally
fsFSArquivoAAC.Free;
end;
end;
Если комментировать флаг FILE_FLAG_NO_BUFFERING, код работает корректно, что указывает на проблему именно с этим флагом.
Подход к решению проблемы
В контексте рассматриваемой проблемы важно отметить, что при использовании FILE_FLAG_WRITE_THROUGH и FILE_FLAG_NO_BUFFERING существуют определенные требования к выравниванию буферов в памяти, выравниванию записей с секторами диска и, возможно, к записи данных порциями, соответствующими размеру сектора. В коде, приведенном выше, эти требования не выполняются.
Рекомендации по исправлению
Обработка ошибок: Важно корректно обрабатывать ошибки, не игнорировать их. Используйте RaiseLastOSError для поднятия последней ошибки ОС.
Выравнивание буферов: Убедитесь, что буферы выровнены по адресу, который является кратным размеру сектора диска.
Размер записи: Размер записываемых данных должен быть кратен размеру сектора диска.
Проверка файловых дескрипторов: Проверяйте файловые дескрипторы сразу после их создания, чтобы убедиться, что они действительны.
Пример исправленного кода
procedure TForm1.btn1Click(Sender: TObject);
var
fsFSArquivoAAC: TFileStream;
L, lastErr: DWORD;
R: WideString;
hFile: THandle;
begin
hFile := Windows.CreateFile(PChar('TesteAAC.AAC2'),
GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ or FILE_SHARE_WRITE, nil, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL or FILE_FLAG_WRITE_THROUGH or FILE_FLAG_NO_BUFFERING, 0);
// Проверка создания файла
if hFile = INVALID_HANDLE_VALUE then
begin
lastErr := GetLastError;
// Обработка ошибки
end;
// Предполагаем, что размер сектора равен 512 байт
SetLength(R, Trunc(512 * 1024 / SizeOf(WideChar)), '#');
L := Length(R);
// Выравнивание данных
L := Trunc(L / SizeOf(WideChar) * SectorAlignment) + SizeOf(WideChar);
SetLength(R, L, '#');
fsFSArquivoAAC := TFileStream.Create(hFile, fmOpenWrite or fmShareCompat);
try
// Запись размера строки
fsFSArquivoAAC.WriteBuffer(L, SizeOf(Integer));
// Запись строки с выравниванием по сектору
fsFSArquivoAAC.WriteBuffer(R[1], L * SizeOf(WideChar));
finally
fsFSArquivoAAC.Free;
Windows.CloseHandle(hFile);
end;
end;
В этом примере предполагается, что размер сектора диска равен 512 байт. Вы должны использовать соответствующее значение для вашего диска. Функция SetLength используется для выравнивания размера строки R по секторам, что является ключевым моментом для успешной записи без буферизации.
Следуя этим рекомендациям, вы сможете избежать ошибки EWriteError и успешно работать с файлами без буферизации в Delphi.
Рассматривается проблема буферизации при работе с файлами в Delphi, связанная с использованием флагов FILE_FLAG_WRITE_THROUGH и FILE_FLAG_NO_BUFFERING, что приводит к ошибке EWriteError и требует корректного выравнивания буферов и размеров зап
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.