既存のファイルのファイルの内容をクリアしますか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
。それは抽象クラスです。代わりにその子孫の 1 つを使用する必要があります (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
はい、はい、正しく読んでいます。間違いではありません。最初の呼び出しは失敗し (try 部分のもの)、2 番目の呼び出しは機能します (except 部分のもの)。
注意: Rewrite でも同じことが起こります。
常に発生するとは限りませんが、リセットまたは書き換えを 1 回だけ行うと、発生したときに I/O エラー 103 が発生します。
最初の試行が失敗した場合を除いて...終了を除いて、リセット/書き換えをやり直すと、2番目の試行は失敗しないことがわかりました。
もちろん、1 つの呼び出しが失敗してはならないケースについて話しているという事実を考慮してください。
これは、Windows 7 および 8/8.1 でのみ発生します (または、少なくとも私が見たものです)。WindowsXP で失敗するのを見たことがありません。
あなたは忠告されています...私はそれが奇妙だと思います!現在、すべての呼び出しを Reset / Rewrite に置き換えて、そのような二重呼び出しを含めるようにしています (最初の呼び出しが失敗した場合は、もう一度再試行してください)。
そして、そのようなトリックが機能します!少なくとも私にとっては!このような 2 番目の呼び出しは決して失敗しません。
重要: 最初の呼び出しが失敗してはならないケースについて話している... 他のケースは考慮していません。
別の言い方をすると:
- 最初の呼び出しが失敗する既知の理由はありません。まったく失敗しないのはすべて正しいことです...しかし、失敗しない場合と失敗する場合があります(Win7/win8/Win8.1の場合)。
リニアコンソールコードでテストしました...同じコード(同じEXE)を複数回実行すると、異なる結果が得られました。
私が言ったように、それは一種の奇妙です...解決策は私が言ったとおりです:最後を除いてリセット/再書き込みをやり直してください。
人間の言葉で言った:
- ドアを (try) 開けられない場合 (try 部分のリセット/書き換え呼び出し)、ドアを開け (部分以外のリセット/書き換え)、できることがわかります (最初に失敗した場合、2 つ目は失敗しません)。
もちろん、OSの不具合を除いて、最初の失敗の既知の理由がない場合!!! 別の形で呼べない!