我已经在Delphi Tokyo中编写了一个例程,该例程接收多个文件(例如CSV)并将它们合并在一起,从而使用户可以选择忽略除第一个文件之外的所有文件的第一行(因为CSV文件通常具有标题行) /列名称行,合并文件时,我只需要一个标题副本。我遇到的问题是,即使我只读取各种输入文件,但是如果文件是在另一个进程(特别是Excel)中打开的,我的应用也会显示错误消息:“无法打开文件。该进程无法访问文件,因为它正在被另一个进程使用。”
我正在使用TStreamReader。我如何告诉TStreamReader应该以只读方式打开文件...并且即使该文件在其他位置打开也可以继续?
以下代码:
procedure glib_MergeTextFiles(const InFileNames: array of string; const OutFileName: string;
HasHeader: Boolean = True;
KeepHeader: Boolean = True);
var
I: Integer;
InStream: TStreamReader;
OutStream: TStreamWriter;
Line: string;
IsFirstLine: Boolean;
begin
// Create our output stream
OutStream := TStreamWriter.Create(OutFileName, False, TEncoding.UTF8);
try
for I := 0 to high(InFileNames) do
begin
InStream := TStreamReader.Create(InFileNames[I], TEncoding.UTF8);
IsFirstLine := True;
try
while not InStream.EndOfStream do
begin
Line := InStream.ReadLine;
if IsFirstLine then { First Line }
begin
if HasHeader = False then
begin
OutStream.WriteLine(Line);
end
else
begin
// Is First Line, Has Header
if I = 0 then {is first file}
OutStream.WriteLine(Line);
end;
end
else
begin
OutStream.WriteLine(Line);
end;
IsFirstLine := False;
end;
finally
InStream.Free;
end;
end;
finally
OutStream.Free;
end;
end;
答案 0 :(得分:5)
问题在于共享模式。默认情况下,流读取器创建一个文件流仅供读取,但未指定共享模式,因此它将打开该文件以进行独占访问。但是,要在其他位置打开文件时打开文件进行读取,必须事先使用FILE_SHARE_READ
标志打开文件以共享读取访问权限:
FILE_SHARE_READ
0x00000001启用文件或设备上的后续打开操作以请求读取访问权限。
否则,其他进程如果请求读取访问权限,则无法打开文件或设备。
如果未指定此标志,但是已打开文件或设备以进行读取访问,则该功能将失败。
您可以将自己的文件流传递给以您喜欢的模式打开的流阅读器:
var
I: Integer;
FileStream: TFileStream;
InStream: TStreamReader;
..
begin
...
FileStream := TFileStream.Create(InFileNames[I], fmOpenRead or fmShareDenyNone);
try
InStream := TStreamReader.Create(FileStream, TEncoding.UTF8);
try
..
同样,这要求Excel在打开文件时执行相同的操作,但是通过我的简单测试,它看起来确实如此。