Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: ファイルスタンプをmsecの部分まで変更するには?


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 8 - Last Post: Oct 3, 2016 4:22 PM Last Post By: osamu nagao
osamu nagao

Posts: 97
Registered: 3/22/04
ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 29, 2016 11:53 PM
nagaoです。 いつも教えて頂き、ありがとうございます。

私のアプリでは、処理したファイルのタイムスタンプが、元のファイルのタイプスタンプ
と違ってしまいます。元のファイルのタイプスタンプと同じに変えるにどのようにすれば
良いでしょうか?

なお、私なりに下記のサンプルプログラムのよううな方法で、それを実現しようとしましたが、
そのサンプルプログラムでは、タイムスタンプの年月日時分秒の部分は指定した通りに
   2017年8月21日13時33分40秒
に変わるのでが、msecの部分は15msecと指定したのに、0msecのままで変わりません。
msecの部分も元のファイルのタイムスタンプを合わせるにはどのようにすればよいでしょうか?

procedure TForm1.Button1Click(Sender: TObject);
var
year,month,day,hour,min,sec,msec:word;
aFilename:string;
aDatetime:tdatetime;
Filehandle:thandle;
Age:integer;
ret:boolean;
begin
if not OpenDialog1.Execute then exit;
aFilename:=OpenDialog1.Filename;
aDatetime:=Encodedate(2017,8,21)
+Encodetime(13,33,40,15);
Age:=DatetimetoFiledate(aDatetime);
Filehandle:=Fileopen(aFilename,fmOpenReadWrite);
try
ret:=(Filesetdate(Filehandle,Age)=0);
finally
Fileclose(Filehandle);
end;
if ret then
Showmessage(' 日付変更に成功しました。')
else Showmessage('日付変更に失敗しました。');
aDateTime:=FileDateToDateTime(Fileage(aFilename));
DecodeDate(aDatetime,year,month,day);
DecodeTime(aDatetime,hour,min,sec,msec);
Showmessage(format('year=%d month=%d day=%d hour=%d min=%d sec=%d msec=%d',[year,month,day,hour,min,sec,msec]));
end;

Edited by: osamu nagao on Sep 30, 2016 17:00
Hikaru FUKUSHI

Posts: 65
Registered: 11/11/02
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 30, 2016 1:08 AM   in response to: osamu nagao in response to: osamu nagao
nagaoさん、こんにちは。福士です。

下記のサンプルプログラムを実行すると、ファイルの年月日時分秒の部分は指定した通りに
   2017年8月21日13時33分40秒
に変わるのでが、msecの部分は15msecと指定したのに、0msecのままで変わりません。
この部分も指定した通りに変更する方法はありませんか?

DelphiのDateTimeToFileDate関数

http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.DateTimeToFileDate

がいわゆるDOSファイル日付(2秒単位)を返すため、それ以下の部分が切り捨てられてしまって
いるのが原因です。

# たとえば13:33:41を指定するとミリ秒どころか秒すら正しく設定できていないことが
# わかります。

この場合、直接Win32APIのSetFileTime関数

https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724933.aspx
https://msdn.microsoft.com/ja-jp/library/cc429940.aspx

を呼び出すのがよいと思います。SetFileTime関数はFILETIME構造体(=DelphiのTFileTime)を
受け取りますので、Win32APIのSystemTimeToFileTime関数

https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724948.aspx
https://msdn.microsoft.com/ja-jp/library/cc429961.aspx

でSYSTEMTIME構造体(= DelphiのTSystemTime)から変換してあげる必要があります。

# ただしファイルのタイムスタンプの精度はOSやファイルシステムによって異なります。

# 投稿中にコードを含む場合は{code}でコード部分を括ると見やすくなります。

--
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fukushi@tts-inc.co.jp

Edited by: Hikaru FUKUSHI on Sep 30, 2016 5:09 PM

osamu nagao

Posts: 97
Registered: 3/22/04
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Sep 30, 2016 11:33 AM   in response to: Hikaru FUKUSHI in response to: Hikaru FUKUSHI
福士さん、こんにちは。nagaoです。
レスくださいましてありがとうございます。

返事頂いたことを読みましたが、私はWin32APIの基礎知識がありませんので、前に進めません。
大変甘えたことを申しますが、Delphi言語でどのようなコードにすればよいのか教えて頂けないでしょうか?

# 投稿中にコードを含む場合は{code}でコード部分を括ると見やすくなります。
分かりました。今後はそのように致します。
Hikaru FUKUSHI

Posts: 65
Registered: 11/11/02
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 1, 2016 1:02 AM   in response to: osamu nagao in response to: osamu nagao
nagaoさん、こんにちは。福士です。

ファイル(およびディレクトリ)の最終更新日時の更新ですが、RTLの

System.IOUtils.TDirectory.SetLastWriteTime - RAD Studio API Documentation
http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.IOUtils.TDirectory.SetLastWriteTime

または

System.IOUtils.TDirectory.SetLastWriteTimeUtc - RAD Studio API Documentation
http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.IOUtils.TDirectory.SetLastWriteTimeUtc

を使用することでファイルシステムの持つ精度まで設定することができるようです(2つの関数の違いは
SetLastWriteTimeでは指定日時を現在のタイムゾーン(例えば日本ならJST(UTC+9h))で
指定するのに対して、SetLastWriteTimeUtcはUTCで指定する)。

これを含め、ファイルやディレクトリ関係は古いSysUtilsのものではなく、新しいIOUtilsのものを
なるべく使ったほうがいいような気がします。

返事頂いたことを読みましたが、私はWin32APIの基礎知識がありませんので、前に進めません。
大変甘えたことを申しますが、Delphi言語でどのようなコードにすればよいのか教えて頂けないでしょうか?

前にも書いた気がしますが、ここはそういう場ではありません。

--
東洋テクニカルシステム株式会社 システム開発部 福士 光
Hikaru Fukushi (Toyo Technical System Inc.)
mailto:fukushi@tts-inc.co.jp
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 1, 2016 11:28 AM   in response to: Hikaru FUKUSHI in response to: Hikaru FUKUSHI
福士さん、こんにちは。nagaoです。
追加のレス頂きましてありがとうございます。

System.IOUtils.TDirectory.SetLastWriteTime - RAD Studio API Documentation
http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.IOUtils.TDirectory.SetLastWriteTime
Delphi 10.1 Berlinで、uses節にSystem.IOUtilsを置いて、下記のコードをコンパイル・実行したところエラー
なく終えることができましたが、Pathhに中に含まれている複数のファイルのタイムスタンプはどれも全く変わ
っていませんでした。
下記のコードの中で間違っているところがあるのでしょうか?
また、SetLastWriteTimeは「ディレクトリーの最終書き込み時刻を変更します。」との説明書きがありますが、
その中の複数のファイルのタイムスタンプもすべてその最終書き込み時刻を変更するということでしょうか?
各ファイルのタイムスタンプは本来は各々異なっている筈なのに、それを同じに揃えてしまうという命令は
おかしいと思うのですが・・・・。
私の理解の仕方が間違っているのではないでしょうか?

{
procedure TForm5.Button2Click(Sender: TObject);
var
aDateTime:TDateTime;
aFileName:string;
Pathh:string;
begin
aDateTime:=EncodeDate(2016,7,20)
+EncodeTime(14,36,41,25);
if not OpenDialog1.Execute then exit;
aFileName:=OpenDialog1.FileName;
Pathh:=ExtractFilePath(aFileName);
TDirectory.SetLastWriteTime(Pathh,aDateTime);
end;
}

なお、上記のコードの中で
TDirectory.SetLastWriteTime(Pathh,aDateTime);
のコードを
TDirectory.SetLastWriteTime(aFileName,aDateTime);
に変更した場合は例外が発生しました。

前にも書いた気がしますが、ここはそういう場ではありません。
分かりました。すみませんでした。
Makoto Saito

Posts: 26
Registered: 12/5/04
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 1, 2016 9:10 PM   in response to: osamu nagao in response to: osamu nagao
TFile を使用してみてください.

https://www.google.co.jp/search?q=delphi+TFile&num=50&biw=1219&bih=875&noj=1&site=webhp&source=lnt&tbs=lr:lang_1ja&lr=lang_ja&sa=X&ved=0ahUKEwi4kOarnbvPAhUJv5QKHQzrDs4QpwUIFg

ヒットした記事は,一応順番に見ていくといいかも知れません.
記事中にあるリンクも確認するといいかも知れません.
記事の中には,関係した記事へのリンクがあることがあります.
ヒットした記事のタイトルだけに惑わされないことです.

コードは,前のレスにあるように {code} でコード部分を括ると見やすくなります.
コードの部分を {code] という文字列で括ります.

参考リンク [ディスカッションフォーラムの使い方]
http://ht-deko.com/tech047.html
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 2, 2016 2:22 PM   in response to: Makoto Saito in response to: Makoto Saito
Makoto Saitoさん、福士さん、こんにちは。nagaoです。
レスくださいましてありがとうございます。

TFile を使用してみてください.

https://www.google.co.jp/search?q=delphi+TFile&num=50&biw=1219&bih=875&noj=1&site=webhp&source=lnt&tbs=lr:lang_1ja&lr=lang_ja&sa=X&ved=0ahUKEwi4kOarnbvPAhUJv5QKHQzrDs4QpwUIFg

ヒットした記事は,一応順番に見ていくといいかも知れません.
記事中にあるリンクも確認するといいかも知れません.
記事の中には,関係した記事へのリンクがあることがあります.
ヒットした記事のタイトルだけに惑わされないことです.

http://mrxray.on.coocan.jp/Delphi/plSamples/780_FileInfoListETC.htm
の中に下記のサイトがありました。
http://www.gesource.jp/weblog/?p=5813
http://www.gesource.jp/weblog/?p=5815
その中のコードそのものでは思うように動作しませんでしたので、少し変えて下記のコードのよう
にしたところ、ファイルの最終書き込み時刻(これは更新日時と同じ意味だと私は理解していま
す。)の取得と変更が正常にできることを確認しました。
なお、下記のコードではmsecの部分の取得と変更はできませんが、それはあきらめることにします。

DelphiのDateTimeToFileDate関数
http://docwiki.embarcadero.com/Libraries/Berlin/ja/System.SysUtils.DateTimeToFileDate
がいわゆるDOSファイル日付(2秒単位)を返すため、それ以下の部分が切り捨てられてしまって
いるのが原因です。
# たとえば13:33:41を指定するとミリ秒どころか秒すら正しく設定できていないことが
# わかります。
下記のコードでは、そのようなことはなく、秒の所まで、正確に読み書きできることを確認
しました。

色々と教えて頂き、ありがとうございました。

unit Unit1;
interface
uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,System.IOUtils, Vcl.StdCtrls;
type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
implementation
{$R *.dfm}
 
procedure TForm1.Button1Click(Sender: TObject);
//ファイルの最終書き込み時刻を取得する
var
  Path: string;
  DateTime : TDateTime;
begin
  OpenDialog1.Execute;
  Path:=OpenDialog1.FileName;
  DateTime := TFile.GetLastWriteTime(Path);
  ShowMessage(FormatDateTime('yyyy/mm/dd hh:nn:ss', DateTime));
end;
 
procedure TForm1.Button2Click(Sender: TObject);
  //ファイルの最終書き込み時刻を変更する
var
  Path: string;
  DateTime: TDateTime;
begin
  DateTime:=EncodeDate(2016,7,23)
     +EncoDetime(5,32,28,225);
  if not OpenDialog1.Execute then exit;
  Path:=OpenDialog1.FileName;
  TFile.SetLastWriteTime(Path, DateTime);
end;
end.
Makoto Saito

Posts: 26
Registered: 12/5/04
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 2, 2016 3:55 PM   in response to: osamu nagao in response to: osamu nagao
その中のコードそのものでは思うように動作しませんでしたので、少し変えて下記のコードのよう
「思うように動作しない」 というのは,コミュニティの場で質問される方がよく使われる表現ですね.
ということは,掲載されているコードが正常に動作しないということですか ?
osamu nagao

Posts: 97
Registered: 3/22/04
Re: ファイルスタンプをmsecの部分まで変更するには?  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Oct 3, 2016 4:22 PM   in response to: Makoto Saito in response to: Makoto Saito
Makoto Saito さん、こんにちは。nagaoです。

「思うように動作しない」 というのは,コミュニティの場で質問される方がよく使われる表現ですね.
ということは,掲載されているコードが正常に動作しないということですか ?
言葉足らずですいみませんでした。

http://www.gesource.jp/weblog/?p=5813
のサイトでは下記のコードが掲載されていますが、
   ShowMessage(FormatDateTime('yyyy/hh/dd hh:nn:ss', DateTime));
では正常に更新日時を読み取れないので、
  ShowMessage(FormatDateTime('yyyy/mm/dd hh:nn:ss', DateTime));
に変更して正常に読み取れるようにしました。

procedure TForm1.ButtonLastWriteTimeClick(Sender: TObject);
var
  Path: string;
  DateTime : TDateTime;
begin
  //最終書き込み時刻を取得したいファイルのパス
  Path := 'C:\sample\file.txt';
  DateTime := TFile.GetLastWriteTime(Path);
  ShowMessage(FormatDateTime('yyyy/hh/dd hh:nn:ss', DateTime));
end;


また、
http://www.gesource.jp/weblog/?p=5815
のサイトでは、下記のコードが掲載されていますが、私が使っているDelphi 10.1 Berlinでは
このコードをコンパイルすると、
DateTime := System.DateUtils.Tomorrow;
の行の中のTomorrowが未定義の識別子と判定されるので、この行を
  DateTime:=EncodeDate(2016,7,23)
   +EncoDetime(5,32,28,225);
に変えました。
また、
  ShowMessage(FormatDateTime('yyyy/hh/dd hh:nn:ss', TFile.GetLastWriteTime(Path)));
の行では上記の通り、正常に更新日時を読み取れないので削除しました。

procedure TForm1.ButtonLastWriteTimeClick(Sender: TObject);
var
  Path: string;
  DateTime: TDateTime;
begin
  // 最終書き込み時刻を変更したいファイルのパス
  Path := 'C:\sample\file.txt';
  // ファイルに適用しようとする新しい最終書き込み時刻
  DateTime := System.DateUtils.Tomorrow;
  // ファイルの最終書き込み時刻を変更する
  TFile.SetLastWriteTime(Path, DateTime);
  ShowMessage(FormatDateTime('yyyy/hh/dd hh:nn:ss', TFile.GetLastWriteTime(Path)));
end;
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02