Учимся работать с многопоточными файлами в NT
01.01.2007
1. Создание(изменение) и чтение "Опциональных потоков"
procedure TForm1.Button1Click(Sender: TObject); begin //сохраняем то что в Memo в "многопоточный файл" Memo1.Lines.SaveToFile('k:\memo.txt'); Memo2.Lines.SaveToFile('k:\memo.txt:memo2'); //опциональный поток end; procedure TForm1.Button2Click(Sender: TObject); begin //читаем в обратном порядке из "многопоточного файла" Memo1.Lines.LoadFromFile('k:\memo.txt:memo2'); //опциональный поток Memo2.Lines.LoadFromFile('k:\memo.txt'); end;
Как видно из первого примера... что бы прочитать "Опциональный поток" нам необходимо знать его "имя"... . Если вам не известно енто "имя", а очень хочется... тогда код 2 пункта предназначен для вас
2. Определяем инфу о файле/директории - читаем инфу о потоках:
*** Не забудьте включить SE_BACKUP_NAME привелегию ***
function InfoFileStreams(const FileName:String; Delete:Boolean; out RStreams:String):Boolean; {Входные данные: - FileName: Имя файла/дирректории. - Delete: Если Truе то... по мимо инфы еще и удаляем "Опциональные потоки" файла. Выходные данные: - True: Что-то смоглы определить :) - RStreams - Определенная инфа} const Error_Buffer_Overflow=$80000005; type _IO_STATUS_BLOCK=packed record Status:DWord; Information:DWord; end; FILE_STREAM_INFORMATION=packed record NextEntry:DWord; NameLength:DWord; Size:Int64; AllocationSize:Int64; Name:WideChar; end; _FILE_INFORMATION_CLASS=(FileDirectoryInformation=1,FileFullDirectoryInformation, FileBothDirectoryInformation,FileBasicInformation, FileStandardInformation,FileInternalInformation, FileEaInformation,FileAccessInformation,FileNameInformation, FileRenameInformation,FileLinkInformation,FileNamesInformation, FileDispositionInformation,FilePositionInformation,FileFullEaInformation, FileModeInformation,FileAlignmentInformation,FileAllInformation, FileAllocationInformation,FileEndOfFileInformation,FileAlternateNameInformation, FileStreamInformation,FilePipeInformation,FilePipeLocalInformation, FilePipeRemoteInformation,FileMailslotQueryInformation,FileMailslotSetInformation, FileCompressionInformation,FileObjectIdInformation,FileCompletionInformation, FileMoveClusterInformation,FileQuotaInformation,FileReparsePointInformation, FileNetworkOpenInformation,FileAttributeTagInformation,FileTrackingInformation, FileMaximumInformation); var NtQueryInformationFile: function (FileHandle:DWord; out IoStatusBlock: _IO_STATUS_BLOCK; FileInformation:Pointer; Length:DWord; FileInformationClass:_FILE_INFORMATION_CLASS):DWord; stdcall; fHandle:DWord; StreamIS:DWord; StreamInfo,tSI:^FILE_STREAM_INFORMATION; IoSB:_IO_STATUS_BLOCK; t:DWord; sN,sT:String; NextEntry,sM:Boolean; begin Result:=false; NtQueryInformationFile:=GetProcAddress(GetModuleHandle('ntdll.dll'),'NtQueryInformationFile'); if Assigned(NtQueryInformationFile)=false then exit; fHandle:=CreateFile(PChar(FileName),GENERIC_READ,FILE_SHARE_READ or FILE_SHARE_WRITE,nil, OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0); if fHandle<>INVALID_HANDLE_VALUE then begin StreamIS:=0; GetMem(StreamInfo,StreamIS); repeat FreeMem(StreamInfo,StreamIS); StreamIS:=StreamIS+16384; GetMem(StreamInfo,StreamIS); t:=NtQueryInformationFile(fHandle,IoSB,StreamInfo,StreamIS,FileStreamInformation); until (t<>Error_Buffer_Overflow); if (t=0)and(IoSB.Information<>0) then begin tSI:=StreamInfo; sN:=''; NextEntry:=True; Result:=true; sM:=false; while NextEntry do begin if tSI^.NextEntry=0 then NextEntry:=false; sT:=Copy(PWideChar(@tSI^.Name),0,tSI^.NameLength div SizeOf(WideChar)); if (sM=false)and(AnsiCompareText(sT,'::$DATA')=0) then begin sM:=true; sN:=sN+'Основной поток: '+sT+'; Размер: '+IntToStr(tSI^.Size)+' байт'+chr($D)+chr($A); end else begin sN:=sN+'Опциональный поток: '+sT+'; Размер: '+IntToStr(tSI^.Size)+' байт'+chr($D)+chr($A); if Delete then if DeleteFile(FileName+sT) then sN:=sN+'Удален!'+chr($D)+chr($A); end; tSI:=Pointer(DWord(tSI)+tSI^.NextEntry); end; RStreams:=sN; end; FreeMem(StreamInfo,StreamIS); CloseHandle(fHandle); end; end;
Ну и до кучи... пример использывания InfoFileStreams:
const SE_BACKUP_NAME = 'SeBackupPrivilege'; function NTSetPrivilege(sPrivilege:string;fEnabled:LongBool):boolean; var hToken:THandle; TokenPriv,PrevTokenPriv:TOKEN_PRIVILEGES; PrivSet:PRIVILEGE_SET; f:LongBool; i:Cardinal; begin Result:=false; if Win32Platform<>VER_PLATFORM_WIN32_NT then exit; PrivSet.PrivilegeCount:=1; PrivSet.Control:=0; PrivSet.Privilege[0].Attributes:=0; if LookupPrivilegeValue(nil,PChar(sPrivilege),PrivSet.Privilege[0].Luid) then if OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,hToken) then begin try if PrivilegeCheck(hToken,PrivSet,f)and(f<>fEnabled) then if LookupPrivilegeValue(nil,PChar(sPrivilege),TokenPriv.Privileges[0].Luid) then begin TokenPriv.PrivilegeCount:=1; if fEnabled then TokenPriv.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED else TokenPriv.Privileges[0].Attributes:=0; i:=0; PrevTokenPriv:=TokenPriv; AdjustTokenPrivileges(hToken,false,TokenPriv,SizeOf(PrevTokenPriv),PrevTokenPriv,i); Result:=GetLastError=ERROR_SUCCESS; end; except end; CloseHandle(hToken); end; end; procedure TForm1.Button1Click(Sender: TObject); var s:string; begin NTSetPrivilege(SE_BACKUP_NAME,true); if InfoFileStreams('k:\memo.txt',false,s) then Memo1.Lines.Text:=s; //Удаляем опциональные потоки //if InfoFileStreams('k:\memo.txt',true,s) then Memo1.Lines.Text:=s; end;
Взято с Vingrad.ru https://forum.vingrad.ru