简体   繁体   English

delphi-重写文件实际上有什么作用?

[英]delphi- what does rewrite file actually do?

Does Rewrite clear file contents of existing file or does it delete it and create a new one? Rewrite清除现有文件的文件内容还是将其删除并创建一个新文件? I have a text file in my app.exe folder which I need to clear. 我的app.exe文件夹中有一个文本文件,需要清除。 Any example? 有什么例子吗?

From the Delphi XE2 documentation, topic Rewrite - read the last quoted paragraph: 在Delphi XE2文档中,主题为“ 重写 -阅读最后引用的段落”:

Creates a new file and opens it. 创建一个新文件并打开它。

In Delphi code, Rewrite creates a new external file with the name assigned to F. 在Delphi代码中,Rewrite创建一个新的外部文件,并将其名称分配给F。

F is a variable of any file type associated with an external file using AssignFile. F是使用AssignFile与外部文件关联的任何文件类型的变量。 RecSize is an optional expression that can be specified only if F is an untyped file. RecSize是一个可选表达式,仅当F为无类型文件时才可以指定。 If F is an untyped file, RecSize specifies the record size to be used in data transfers. 如果F是一个无类型的文件,则RecSize指定要在数据传输中使用的记录大小。 If RecSize is omitted, a default record size of 128 bytes is assumed. 如果省略RecSize,则假定默认记录大小为128字节。

If an external file with the same name already exists, it is deleted and a new empty file is created in its place. 如果已经存在相同名称的外部文件,则将其删除并在其位置创建一个新的空文件。

From the same documentation, link at the bottom of page for System.Rewrite , modified to use your app's folder: 从同一文档中,页面底部的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;

You should know, though, that Rewrite is outdated and doesn't support Unicode. 但是,您应该知道Rewrite已经过时并且不支持Unicode。 You should be using more modern methods to read and write files like TFileStream or TStringWriter (or even the simple solution of TStringList ). 您应该使用更现代的方法来读写文件,例如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;

Note that you cannot use TStrings ; 注意您不能使用TStrings ; it's an abstract class. 这是一个抽象类。 You need to use one of it's descendants instead ( TStringList is the one used most often). 您需要使用它的后代之一( TStringList是最常用的后代)。

I did an experiment and determined that REWRITE overwrites an existing file. 我做了一个实验,确定REWRITE会覆盖现有文件。 It does not delete and then recreate the file. 它不会删除,然后重新创建文件。 You'll have to learn a little about file tunneling, something I knew nothing about when I began. 您将必须学习一些有关文件隧道的知识,而我刚开始时对此一无所知。

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.

Worst case i have noticed when working with Reset and Rewrite: 使用复位和重写时,我注意到最坏的情况:

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

Output that i had never ever think it could be possible: 1 3 4 我从未想过的输出:1 3 4

Yes, yes, you are reading correctly, it is not a mistake: first call fails (the one in try part) and second one works (the one on except part). 是的,是的,您正在正确阅读,这不是一个错误:第一次调用失败(尝试部分中的一个),第二个调用成功(除去部分中的一个)。

Please note: Also happens the same with Rewrite. 请注意:重写也会发生同样的情况。

That not allways happen, but if you let only one Reset or Rewrite, when taht would happen you will get an I/O error 103. 并非总会发生这种情况,但是如果只允许进行一次“重置”或“重写”,那么在发生这种情况时,您将收到I / O错误103。

I had seen that if i re-do the Reset / Rewrite on a try...except...end if the first one fails the second one does not fail. 我已经看到,如果我尝试执行重设/重写操作...例外...结束,如果第一个失败,第二个也不会失败。

Of course, considering the fact that i am talking of cases where one single call must not fail. 当然,考虑到我所说的事实,即一个电话一定不会失败。

This happens (or at least is what i have seen) only on Windows 7 and 8/8.1 ... i had never see them to fail on WindowsXP. 仅在Windows 7和8 / 8.1上才发生(或至少是我所看到的)……我从未见过它们在WindowsXP上失败。

You're advised... i think it is weird! 建议您...我认为这很奇怪! Now i am replacing all calls to Reset / Rewrite so to include such double call (if first call fail re-try a second time). 现在,我将替换所有对“重置/重写”的调用,以便包括这样的双重调用(如果第一次调用失败,请再次尝试第二次)。

And such trick works! 这样的技巧行得通! At least for me! 至少对我来说! Such second call has never fail. 这样的第二次呼叫从未失败。

IMPORTANT: I am talking about cases where that first call must not fail... i am not considering any other cases. 重要提示:我说的是第一次通话一定不会失败的情况……我没有考虑其他任何情况。

Said in another way: 用另一种方式说:

  • There is no known reason why first call would fail, all is correct for it to not to fail at all... but sometimes it does not fail while others it does fail (on Win7/win8/Win8.1). 没有已知的原因导致第一次调用失败,这是完全正确的,因为它根本不会失败...但是有时它不会失败,而其他人确实会失败(在Win7 / win8 / Win8.1上)。

Tested on linear console code... run multiply times same code (same EXE), got different results. 在线性控制台代码上进行了测试...将相同代码(相同EXE)相乘多次,得到不同的结果。

As i said it is kind weird... solution is as i said: Redo Reset / Rewrite on a try except end. 正如我说的那样,这很奇怪...解决方案就像我说的那样:重试重置/重写,但尝试结束。

Said in human words: 用人类的话说:

  • If you can not (try) open the door (Reset/Rewrite call in try part), open the door (Reset/Rewrite on except part) and you will see you can (if first fails, second does not fail). 如果您不能(尝试)打开门(尝试部分中的“重置/重写”调用),请打开门(除了部分上的“重置/重写”),您会看到可以的(如果第一个失败,第二个不会失败)。

That of course if there is no known reason for first one to fail, except OS glitch !!! 当然,如果没有已知的原因导致第一个失败,除了操作系统故障之外!!! I can not call it in another form! 我不能用其他形式称呼它!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM