是清除现有文件的文件内容还是删除它Rewrite
并创建一个新文件?我的app.exe文件夹中有一个需要清除的文本文件。有什么例子吗?
3 回答
从 Delphi XE2 文档中,主题Rewrite - 阅读最后引用的段落:
创建一个新文件并打开它。
在 Delphi 代码中,Rewrite 会创建一个名为 F 的新外部文件。
F 是与使用 AssignFile 的外部文件关联的任何文件类型的变量。RecSize 是一个可选表达式,仅当 F 是无类型文件时才能指定。如果 F 是无类型文件,则 RecSize 指定要在数据传输中使用的记录大小。如果省略 RecSize,则假定默认记录大小为 128 字节。
如果已存在同名的外部文件,则将其删除并在其位置创建一个新的空文件。
在同一文档中,页面底部的链接System.Rewrite
,修改为使用您的应用程序的文件夹:
procedure TForm1.Button1Click(Sender: TObject);
var
F: TextFile;
AppDir: string;
begin
// Instead of ParamStr(0), you can use Application.ExeName
// if you prefer
AppDir := ExtractFilePath(ParamStr(0));
AssignFile(F, AppDir + 'NEWFILE.$$$');
Rewrite(F); // default record size is 128 bytes
Writeln(F, 'Just created file with this text in it...');
CloseFile(F);
MessageDlg('NEWFILE.$$$ has been created in the ' + AppDir + ' directory.',
mtInformation, [mbOk], 0, mbOK);
end;
但是,您应该知道,它Rewrite
已经过时并且不支持 Unicode。您应该使用更现代的方法来读取和写入文件,例如TFileStream或TStringWriter(甚至是TStringList的简单解决方案)。
var
SL: TStringList;
AppDir: string;
begin
AppDir := ExtractFilePath(ParamStr(0));
SL := TStringList.Create;
try
SL.Add('Just created file with this text in it...');
// Add more lines here if needed, and then only save once
SL.SaveToFile(AppDir + 'NEWFILE.$$$');
MessageDlg('NEWFILE.$$$ has been created in the ' + AppDir + ' directory.',
mtInformation, [mbOk], 0, mbOK);
finally
SL.Free;
end;
end;
请注意,您不能使用TStrings
; 这是一个抽象类。您需要改用它的后代TStringList
之一(是最常使用的后代)。
我做了一个实验,并确定 REWRITE 会覆盖现有文件。它不会删除然后重新创建文件。你必须学习一点关于文件隧道的知识,这是我刚开始时一无所知的东西。
program RewriteTest;
{$APPTYPE CONSOLE}
uses
SysUtils,
Windows;
//========================================================================
// Will REWRITE delete an existing file and create a new file,
// or will it overwrite the existing file?
//------------------------------------------------------------------------
// According to the Delphi documentation, it will delete the old file and
// create a new one. But is this true?
// Internally, it calls the Windows API CreateFile function with the
// CREATE_ALWAYS option.
// The Microsoft documentation for CreateFile says this will overwrite the
// existing file.
// Let's perform an experiment to see what really happens.
// Here are the steps in the experiment:
//
// 1. Select a file name.
// 2. Delete that file if it exists.
// 3. Create a file with that name.
// 4. Determine the creation time of that file. Call it A.
//
// - - As with any experiment, we first need a control case.
// We will explicitly delete the file we just created
// and then recreate the file.
//
// 5. Wait a few seconds.
// 6. Delete the file that was just created.
// 7. Again, create a file with that same name.
// 8. Determine the creation time of this new file. Call it B.
//
// - - We would expect that since the first file was deleted,
// and a new file was created, that the creation times of
// these files would be different.
// I was quite surprised to find that this hypothesis
// is WRONG!
// This is why scientific experiments have controls!
//
// Two separate files created at distinct times had the same
// Creation Date according to the operating system.
//
// - - TUNNELING: It turns out our experimental results were gummed up
// by something I knew nothing about before, called file tunneling.
// The Windows operating system has this feature which will save the
// existing meta-information about a file for "a short time" after it
// is deleted or renamed.
// If another file is created with the same name, or renamed
// to that name, the new file will be assigned the same meta-data
// as the original.
// I won't go too far into this topic here. If you're interested you
// can research it yourself. I'll just say two things about it.
// There's a very good reason for it. And it can be turned off.
//
// To turn it off, you need to edit the registry.
// WARNING: Don't edit the registry unless you know what you are doing.
// You could damage your operating system.
//
// [a] Go to key:
// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem
//
// [b] Create a dword value named MaximumTunnelEntries and set it to zero.
//
// [c] Reboot.
//
// Remember to put everything back the way it was when you're done.
//
// - - Did it work? Rerun the experiment above and note that the file
// creation times are now different.
// Now to continue with our experiment.
// What will happen if we call REWRITE without first deleting the file?
// Will it delete the existing file and create a new one?
// Or will it overwrite the existing file?
//
// 9. Wait a few seconds.
// 10. Without first explicitly deleting the file,
// call REWRITE with the same file name.
// 11. Determine the creation time of this new file. Call it C.
//
// 12. Compare B to C. If they are the different, then the file must've
// been deleted. If they are the same, then the file was overwritten.
//
// - - CONCLUSION: The file creation times are the same. Calling rewrite
// did not delete the existing file. Rather it was overwritten.
//
//==============================================================================
{ 1. select a file name }
const
gFileName : string = 'rewrite-test.txt';
procedure DeleteFileIfItExists;
begin
if FileExists ( gFileName ) then
if not SysUtils.DeleteFile ( gFileName ) then
raise exception . create ( 'Cannot delete existing file.' );
end; // DeleteFileIfItExists
procedure CreateTheFile;
var
aTextFile : textfile;
begin
assignfile ( aTextFile, gFileName );
rewrite ( aTextFile );
try
// To make the experiment more realistic, write something to the file.
writeln ( aTextFile, 'Current time is: ', DateTimeToStr ( Now ) );
finally
closefile ( aTextFile );
end;
end; // CreateTheFile
function DetermineFileCreationDate : tDateTime;
var
aFileHandle : tHandle;
aCreationTime : tFileTime;
aSystemTime : tSystemTime;
begin
aFileHandle := CreateFile ( pchar(gFileName),
GENERIC_READ,
FILE_SHARE_READ,
nil,
OPEN_EXISTING,
0,
0 );
if aFileHandle = INVALID_HANDLE_VALUE then
raise exception . create ( 'Cannot open file' );
try
GetFileTime ( aFileHandle,
@ aCreationTime,
nil,
nil );
finally
CloseHandle ( aFileHandle );
end;
if not FileTimeToSystemTime ( aCreationTime, aSystemTime ) then
raise exception . create ( 'Cannot convert file time' );
Result := SysUtils . SystemTimeToDateTime ( aSystemTime );
end; // DetermineFileCreationDate
procedure WaitAFewSeconds;
begin
sleep ( 5000 ); // 5 seconds should be enough
end;
procedure RunExperiment;
var
A : tDateTime;
B : tDateTime;
C : tDateTime;
begin
{ 2.} DeleteFileIfItExists;
{ 3.} CreateTheFile;
{ 4.} A := DetermineFileCreationDate;
{ 5.} WaitAFewSeconds;
{ 6.} DeleteFileIfItExists;
{ 7.} CreateTheFile;
{ 8.} B := DetermineFileCreationDate;
if A = B then
raise exception . create ( 'The control file times are the same.'
+ #13'Turn off file tunneling.'
+ #13'See notes and warnings.' );
{ 9.} WaitAFewSeconds;
{10.} CreateTheFile;
{11.} C := DetermineFileCreationDate;
writeln ( 'The original creation time was ', DateTimeToStr ( B ) );
writeln ( 'The new creation time is ', DateTimeToStr ( C ) );
if B = C then
begin
// This is the one
writeln ( 'The file creation times are not the same.' );
writeln ( 'REWRITE overwrites the existing file.' );
end
else
begin
// This is not run
writeln ( 'The file creation times are the same.' );
writeln ( 'REWRITE deletes and recreates the file.' );
end;
end; // RunExperiment
begin
try
writeln ( 'The test will take about 10 seconds. Please wait.' );
RunExperiment;
// Give user a chance to see the answer
writeln ( 'Press Enter to continue' );
readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
我在使用重置和重写时注意到的最坏情况:
try
ShowMessage('1');
Reset(MyFile);
ShowMessage('2');
except
ShowMessage('3');
Reset(MyFile);
ShowMessage('4');
end;
我从未想过有可能的输出:1 3 4
是的,是的,您没看错,这不是错误:第一次调用失败(尝试部分中的那个),第二个调用失败(除了部分中的那个)。
请注意:重写也会发生同样的情况。
这并非总是会发生,但如果您只让一个 Reset 或 Rewrite 发生,那么当发生这种情况时,您将收到 I/O 错误 103。
我已经看到,如果我尝试重新执行重置/重写...除了...结束,如果第一个失败,第二个不会失败。
当然,考虑到我说的是一个单一的呼叫不能失败的情况。
这种情况仅在 Windows 7 和 8/8.1 上发生(或者至少是我所看到的)......我从未见过它们在 WindowsXP 上失败。
建议您...我认为这很奇怪!现在我正在替换所有对 Reset / Rewrite 的调用,以便包括这样的双重调用(如果第一次调用失败重试第二次)。
这样的伎俩有效!至少对我来说!这样的第二次呼叫从未失败。
重要提示:我说的是第一次通话不能失败的情况......我不考虑任何其他情况。
换一种方式说:
- 第一次调用失败的原因没有已知的原因,完全不失败是正确的……但有时它不会失败,而其他人确实会失败(在 Win7/win8/Win8.1 上)。
在线性控制台代码上测试...运行多次相同的代码(相同的 EXE),得到不同的结果。
正如我所说,这很奇怪......解决方案正如我所说:重做重置/尝试重写,除了结束。
用人的话说:
- 如果您不能(尝试)打开门(尝试部分中的重置/重写调用),请打开门(除部分之外的重置/重写),您会看到可以(如果第一次失败,第二次不会失败)。
当然,如果没有已知原因导致第一个失败,除了操作系统故障!!!我不能用另一种形式来称呼它!