흥미로운 문제가 있습니다. 우리 고객이 전화 통화로 음성 대화를 녹음했지만 녹음 파일에 지정된 파일 이름이 유효하지 않습니다. 여기 123:123.wmv
폴더에서 잘못된 FileNames 읽기.
이 믿거 파일 이름의 예는, 윈도우 미디어 인코더는 파일을 생성하고, 모든 정보는하지만 Windows가 분명히 파일 이름을 인식하지 않으며, 단지 123
같은 폴더에 표시, 파일에 파일이 0KB입니다
글쎄, 여기에서 그것은 편집됩니다 : 올바른 방향으로 나를 가리킨 키이스 밀러 덕분에 파일에서 스트림 이름을 추출하고 그것을 사용하는 함수를 작성할 수 있습니다.
두 개의 데이터 스트림을 파일로 작성하고 스트림 이름을 읽고 각 스트림에서 데이터를 읽는 방법에 대한 작업 사본을 포함했습니다. 이것은 정말 끝내 주므로 다른 사람들도 이것을 사용할 수 있기를 바랍니다. 내 코드가 기본 스트림을 무시합니다. 기본 스트림에 데이터를 쓰는 경우 무시하지 않는 것이 가장 좋습니다.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, uGeneralStuff;
type
_FILE_STREAM_INFORMATION = record
NextEntryOffset: cardinal;
StreamNameLength: cardinal;
StreamSize: int64;
StreamAllocationSize: int64;
StreamName: array[0..MAX_PATH] of WideChar;
end;
PFILE_STREAM_INFORMATION = ^_FILE_STREAM_INFORMATION;
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
InfoBlock: _FILE_STREAM_INFORMATION;
StatusBlock : record
Status: Cardinal;
Information: PDWORD;
end;
procedure CreateFile(FileName, Info: String);
function ReadFile(FileName: String): String;
function ReadStreams(filename: String): TStringList;
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
function NtQueryInformationFile(FileHandle : Cardinal;
IoStatusBlock : Pointer;
FileInformation : Pointer;
FileInformationLength : Cardinal;
FileInformationClass : Cardinal
): Cardinal; stdcall; external 'ntdll.dll';
implementation
uses Math, StrUtils;
{$R *.dfm}
function TForm1.ReadStreams(filename: String): TStringList;
var
iFH1: Integer;
aFileName: array[0..MAX_PATH] of WideChar;
aStreamName: String;
begin
Result := TStringList.Create;
iFH1 := FileOpen(filename, GENERIC_READ);
NtQueryInformationFile(iFH1, @StatusBlock, @InfoBlock, SizeOf(InfoBlock), 22); // 22 Means FileStreamInformation
FileClose(iFH1);
while (1=1) do
begin
if InfoBlock.StreamNameLength = 0 then
break;
CopyMemory(@aFileName, @InfoBlock.StreamName, InfoBlock.StreamNameLength);
aStreamName := Copy(aFileName, 1, PosEx(':', aFileName, 2) - 1);
if aStreamName <> ':' then //Ignore main stream, because I know I didn't write data in there
Result.Add(aStreamName);
if (InfoBlock.NextEntryOffset = 0) then
break;
InfoBlock := PFILE_STREAM_INFORMATION(PByte(@InfoBlock) + InfoBlock.NextEntryOffset)^;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
aStreams: TStringList;
I: Integer;
begin
aStreams := ReadStreams('C:\Temp\123');
for I := 0 to aStreams.Count - 1 do
begin
ShowMessage(ReadFile('C:\Temp\123' + aStreams[I]));
end;
end;
procedure TForm1.CreateFile(FileName, Info: String);
var
iFH1: Integer;
Buffer: PAnsiString;
begin
iFH1 := FileCreate(FileName);
Buffer := PAnsiString(AnsiString(Info) + #0);
FileWrite(iFH1, Buffer^, Length(Info));
FileClose(iFH1);
end;
function TForm1.ReadFile(FileName: String): String;
var
iFH1: Integer;
Buffer: PAnsiChar;
iFL: Integer;
iBR, iCurPos, iReadSize: Integer;
begin
iFH1 := FileOpen(FileName, GENERIC_READ);
iFL := FileSeek(iFH1, 0, 2);
FileSeek(iFH1, 0, 0);
iReadSize := Min(iFL, 1024);
Buffer := AllocMem(iReadSize + 1);
iCurPos := 0;
Result := '';
while iCurPos < iFL do
begin
iBR := FileRead(iFH1, Buffer^, iReadSize);
if iBR = -1 then
break;
Result := Result + Buffer;
Inc(iCurPos, iBR);
end;
FileClose(iFH1);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
CreateFile('C:\Temp\123:123.txt', 'This is TestFile 1');
CreateFile('C:\Temp\123:345.txt', 'This is TestFile 2');
ShowMessage(ReadFile('C:\Temp\123:123.txt'));
ShowMessage(ReadFile('C:\Temp\123:345.txt'));
end;
end.
큰 따옴표로 파일 이름을 넣으려고 했습니까?위의 예제 중 하나를 사용하여 파일을'' "C : \ Temp \ 123 : 345.txt" ''로 참조하십시오. –
@ Jerry, Jaque는 이미 파일을 여는 것이 문제가 아니라고 말했습니다. 문제는 파일의 이름 *을 발견하는 것입니다. Explorer와'FindFirstFile' 모두 나머지 이름없이 "123"만 표시합니다. 무엇을 넣을 지 모를 때는 따옴표 안에 넣을 수 없습니다. –
미안하지만 나는 그것을 잡지 않았다. 자,'FindFirstFileEx()'의 유니 코드 버전을 사용해 보셨습니까? 찾고자하는 패턴의 처음에''\\? \ ''를 두는 것을 잊지 마십시오 (모든 파일에 대해''\\? \ *' '). –