delphi-重写文件实际上做了什么?

时间:2012-06-03 03:03:42

标签: delphi

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

3 个答案:

答案 0 :(得分: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是最常用的)。

答案 1 :(得分: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.

答案 2 :(得分:0)

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

try
   ShowMessage('1');
   Reset(MyFile);
   ShowMessage('2');
except
      ShowMessage('3');
      Reset(MyFile);
      ShowMessage('4');
end;

我从未想过的输出是可能的:1 3 4

是的,是的,你正确阅读,这不是一个错误:第一次调用失败(尝试部分中的那个)和第二个调用(除了部分之外的那个)。

请注意:Rewrite也是如此。

这并非总是发生,但如果你只让一次重置或重写,当发生这种情况时,你会得到一个I / O错误103.

我曾经看过,如果我重新尝试重置/重写...除了...如果第一个失败则结束第二个不会失败。

当然,考虑到我所说的一个单一呼叫不能失败的情况。

仅在Windows 7和8 / 8.1上发生这种情况(或者至少是我所看到的)...我从未在WindowsXP上看到它们失败。

你被告知......我觉得这很奇怪!现在我将所有调用替换为Reset / Rewrite,以包含这样的双重调用(如果第一次调用失败,则重新尝试第二次)。

这样的伎俩有效!至少对于我来说!这样的第二次通话永远不会失败。

重要提示:我说的是第一次电话不能失败的情况......我不会考虑任何其他情况。

以另一种方式说:

  • 没有任何已知的原因,为什么第一次调用会失败,一切都是正确的,它根本不会失败...但有时它不会失败,而其他它失败(在Win7 / win8 / Win8.1上)。

在线性控制台代码上测试...运行乘以相同代码(相同的EXE),得到不同的结果。

正如我所说的那样有点奇怪...解决方案正如我所说:重做重置/重写尝试除了结束。

用人的话说:

  • 如果您不能(尝试)打开门(在试用部件中重置/重写调用),打开门(重置/重写除了部分)你会看到你可以(如果第一次失败,第二次没有失败)

当然,如果没有任何已知的理由让第一个失败,除了O.S.小故障!!!我不能用另一种形式来称呼它!