1

是清除现有文件的文件内容还是删除它Rewrite并创建一个新文件?我的app.exe文件夹中有一个需要清除的文本文件。有什么例子吗?

4

3 回答 3

5

从 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。您应该使用更现代的方法来读取和写入文件,例如TFileStreamTStringWriter(甚至是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之一(是最常使用的后代)。

于 2012-06-03T03:09:42.517 回答
3

我做了一个实验,并确定 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.
于 2012-06-03T20:34:57.767 回答
0

我在使用重置和重写时注意到的最坏情况:

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),得到不同的结果。

正如我所说,这很奇怪......解决方案正如我所说:重做重置/尝试重写,除了结束。

用人的话说:

  • 如果您不能(尝试)打开门(尝试部分中的重置/重写调用),请打开门(除部分之外的重置/重写),您会看到可以(如果第一次失败,第二次不会失败)。

当然,如果没有已知原因导致第一个失败,除了操作系统故障!!!我不能用另一种形式来称呼它!

于 2014-10-14T13:24:05.003 回答