ストレージにあるファイルのタイムスタンプが変更できない。

673 views
Skip to first unread message

ケシポン

unread,
Sep 15, 2017, 12:40:11 AM9/15/17
to 日本Androidの会
File.setLastModifiedを使っているのですが、ファイルのタイムスタンプが変わりません。
他に方法などはあるのでしょうか?

Tatsuo Nagamatsu

unread,
Sep 15, 2017, 12:55:15 AM9/15/17
to android-g...@googlegroups.com
FYI,

Android Oから sdcardfsが導入されているようです。

Nexus and Pixel Devices Migrate to SDCardFS in Android O

|  eliminate odd PC file transfer errors such as incorrect time-stamps being shown on your photos.

https://www.xda-developers.com/nexus-pixel-devices-migrate-to-sdcardfs-in-android-o/

タイムスタンプの問題が修正されているそうなので Android Oでは正しく動作するのかもね。

--


2017-09-15 13:40 GMT+09:00 ケシポン <xl120...@gmail.com>:
File.setLastModifiedを使っているのですが、ファイルのタイムスタンプが変わりません。
他に方法などはあるのでしょうか?

--
このメールは Google グループのグループ「日本Androidの会」に登録しているユーザーに送られています。
このグループから退会し、グループからのメールの配信を停止するには android-group-japan+unsub...@googlegroups.com にメールを送信してください。
このグループに投稿するには android-group-japan@googlegroups.com にメールを送信してください。
https://groups.google.com/group/android-group-japan からこのグループにアクセスしてください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

dodo

unread,
Sep 17, 2017, 1:27:43 AM9/17/17
to 日本Androidの会
こんにちは、dodoと申します。

本件、私も興味が出て調べてみましたが、 File.setLastModified()が
使えないのはandroidの昔からの既知の問題のようです。

テストプロを作って試しましたが、手持ちのNexus 5(Android 6.0.1)でも
File.setLastModified()は常にfalseが返り、セットできませんでした。

そこで、不完全ではあるものの代替策を考えて試してみましたのでご紹介します。
androidのshell上にlinuxのtouch コマンドがあります。実際はtoyboxのシンボリックリンクですが、
このコマンドでファイルのタイムスタンプを変えることができます。
そこで、androidアプリからProcessクラスオブジェクトを介して
このコマンドを実行します。以下のようなメソッドを作成して

  private String executeCommand(String command) {
        try {
            Process process = Runtime.getRuntime().exec(command);

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(process.getInputStream()));
            int read;
            char[] buffer = new char[4096];
            StringBuffer output = new StringBuffer();
            while ((read = reader.read(buffer)) > 0) {
                output.append(buffer, 0, read);
            }
            reader.close();

            process.waitFor();

            String outText = output.toString();
            Log.d(TAG, "out: " + outText);  
            return outText;
        } catch (IOException e) {
            Log.w(TAG, "IOException: " + e.getMessage());
        } catch (InterruptedException e) {
            Log.w(TAG, "InterruptedException: " + e.getMessage());
        }
        return "";
    }

以下のように呼び出すと、/sdcard/Download/data.txt のタイムスタンプが現在日時に変わります。
  executeCommand("/system/bin/touch /sdcard/Download/data.txt");

「不完全であるものの」と上で書いたのは、とりあえず以下のような理由があるからです。
1. /system/bin/touchコマンドはコマンドラインオプション指定でどうも問題があるようで、
  例えば日時指定 "-t"を指定しても指定した日時でセットされない。
つまり、androidアプリからProcessクラスオブジェクトを介しても指定したい日時にセットできない。

2. 外部ストレージでマウントしたSDカードではファイルシステムが違う(exFATやFAT32?)
 だろうから、ファイルシステムドライバーのキャッシュ方法の違いが顕在化して、
 上記の方法でもダメかもしれない。

3. shellの環境が違うandroid端末もあるだろうから、/system/bin/touch が使えるとは限らない。

/system/bin/touch のソースコードを見たところ、linuxのシステムコール
utimensat() を使っているので、NDKでこのシステムコールを直に呼び出せば
touchコマンドに依存しないで日時設定できるようになると思います。(未確認です)

dodo


2017年9月15日金曜日 13時40分11秒 UTC+9 ケシポン:
File.setLastModifiedを使っているのですが、ファイルのタイムスタンプが変わりません。
他に方法などはあるのでしょうか?

dodo

unread,
Sep 17, 2017, 5:18:48 AM9/17/17
to 日本Androidの会
dodoです。連続での投稿失礼します。一部自己レスです。

> /system/bin/touch のソースコードを見たところ、linuxのシステムコール
> utimensat() を使っているので、NDKでこのシステムコールを直に呼び出せば
> touchコマンドに依存しないで日時設定できるようになると思います。(未確認です)

についてですが、NDK/JNIでandroidアプリからutimensat() システムコールを
呼び出してタイムスタンプをセットするテストプロを作成し、試してみました。
結果はNGで、 /sdcard/Download/test.txt へのセットでは
utimenstat()のリターンコード=-1, errno=1(EPERM) "Operation not permitted" でした。
アプリのパーミッションでシステムコールを呼び出すので、
ディレクトリのパーミッション設定ではねられるようです。 (考えてみれば当たり前) 

Processクラスオブジェクトを介して、androidの管理下で適切な権限で
実行する必要がありそうです。
Reply all
Reply to author
Forward
0 new messages