Is it possible to create new file with some specific old date?

623 Views Asked by At

In my Android application I have a feature of renaming files. I have implemented this feature by creating a new file with new name on same path and then copying the content of original file to new file after all that I delete the file with old name.

The problem here is that the timestamp of the original file is not retained and the renamed file gets created with time when it was renamed.

What I have tried so far

1- I used file.renameTo() function.

2- 1 never works so I used setLastModified method for new file and passed it the last modified date of original file. Got this last modified date by using existingFile.lastModified().

3- After that in function where i am fetching files using Media Store I sorted the files by DATE_MODIFIED

4- Point 3 doesn't worked properly as it keeps showing renamed file on top with original file date, so I removed Sort by DATE_MODIFIED from media store and tried fetchedFiles.sortByDescending { it.getMFileDate() }

5- Point 4 also have same issue the renamed file shows up on top.

Code for renameTo function usage that didn't work properly

           try {

            val existingFile = File(selectedFile.getMAbsolute_path())
            val separator = "."
            val arrValues: Array<String> =
                selectedFile.getMAbsolute_path()?.split(separator)!!.toTypedArray()
            val newFileName = inputText
            val newFilePath =
                selectedFile.getMParent_file() + "/$newFileName.${arrValues[arrValues.size - 1]}"
            val newFile = File(newFilePath)
            existingFile.renameTo(newFile)

        } catch (e: Exception) {
            e.printStackTrace()
        }

The above code renames the file on device version 8 but on Android version 7 it just removes the file. It doesn't shows up same results on different devices

Below is my current code:

Permissions

 <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
    <uses-permission android:name="com.android.launcher.permission.READ_PHONE_STATE" />

UPDATED [23-12-2020]

I have made changes to proceedRenaming function, first i created new file object then copied it, after that i have set lastModified and at the end Media Store scan is called. This is the right call hierarchy. It works fine on devices greater than or equal to Android Version 8 (OREO). I have figured out the setLastModified function is not working on devices below Android Version 8 (OREO). It keeps on setting the current date to new file.

Rename Function

 private fun proceedRenaming(
    context: Context,
    selectedFile: MyFileModel,
    positionOfDeleted: Int,
    inputText: String,
    isFileShortcutCreated: Boolean
) {
    try {
        //delete shortcut if exists
        deleteFileShortCut(context, selectedFile, positionOfDeleted)
        val existingFile = File(selectedFile.getMAbsolute_path())
        val separator = "."
        val arrValues: Array<String> =
            selectedFile.getMAbsolute_path()?.split(separator)!!.toTypedArray()
        val newFileName = inputText
        val newFilePath = selectedFile.getMParent_file() + "/$newFileName.${arrValues[arrValues.size - 1]}"
            val newFile = File(newFilePath)
            copy(existingFile, newFile)
            //print the original last modified date
            val sdf = SimpleDateFormat("MM/dd/yyyy")
            val date1 = "" + sdf.format(existingFile.lastModified())
            Log.d("Origina Date :", date1)

            //set this date
            //need convert the above date to milliseconds in long value
            val newDate: Date = sdf.parse(date1)
            newFile.setLastModified(newDate.time)
            //print the latest last modified date
            val date2 = "" + sdf.format(newFile.lastModified())
            Log.i("Lastest Date : ", date2)


            context?.sendBroadcast(
                Intent(
                    Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,
                    Uri.fromFile(newFile)
                )
            )
        if (existingFile.exists()) {
            existingFile.delete()
            existingFile.canonicalFile.delete()
            if (existingFile.exists()) {
                BaseApplication.applicationContext()
                    .deleteFile(existingFile.getName())
            }
        }
        MediaScannerConnection.scanFile(
            context,
            arrayOf<String>(selectedFile.getMAbsolute_path().toString()),
            null
        ) { path, uri ->
            Log.i("ExternalStorage", "Scanned $path:")
            Log.i("ExternalStorage", "-> uri=$uri")
            context?.contentResolver
                ?.delete(uri, null, null)

        }

        selectedFile.setOldFileName(selectedFile.getMFile_name()!!)
        selectedFile.setOldFileParentFileh(selectedFile.getMParent_file()!!)
        selectedFile.setOldFilePath(selectedFile.getMAbsolute_path()!!)
        selectedFile.setMAbsolute_path(newFilePath)
        selectedFile.setMFile_name(newFileName)
        selectedFile.setPosition(positionOfDeleted)
        renamedFile.postValue(selectedFile)
        if (isFileShortcutCreated) {
            createFileShortCut(context, selectedFile, positionOfDeleted)
        }
    } catch (e: Exception) {
        e.printStackTrace()
        Toast.makeText(
            context,
            context?.getString(R.string.text_rename_error),
            Toast.LENGTH_SHORT
        ).show()
    }
}

Copy Function

@Throws(IOException::class)
    fun copy(src: File?, dst: File?) {
        val inStream = FileInputStream(src)
        val outStream = FileOutputStream(dst)
        val inChannel: FileChannel = inStream.getChannel()
        val outChannel: FileChannel = outStream.getChannel()
        inChannel.transferTo(0, inChannel.size(), outChannel)
        inStream.close()
        outStream.close()
    }

Function Where I am fetching files from MediaStore

private fun readFiles(
    args: Array<String?>,
    where: String
): ArrayList<MyFileModel> {
    val fetchedFiles = ArrayList<MyFileModel>()
    var fileCursorExternal: Cursor? = null
    var fileCursorInternal: Cursor? = null
    try {
    //Tables
        val tableExternal = MediaStore.Files.getContentUri("external")
        val tableInternal = MediaStore.Files.getContentUri("internal")

    //Column
        val column = arrayOf(
            MediaStore.Files.FileColumns.DATE_ADDED,
            MediaStore.MediaColumns.DATA,
            MediaStore.MediaColumns.TITLE,
            MediaStore.MediaColumns.SIZE,
            MediaStore.Files.FileColumns.DATE_MODIFIED
        )

    //Sort by date
        val orderBy = MediaStore.Files.FileColumns.DATE_MODIFIED

        fileCursorExternal = context.contentResolver.query(
            tableExternal,
            column,
            where,
            args, "$orderBy DESC"
        )
        while (fileCursorExternal!!.moveToNext()) {
            fetchedFiles.add(setMyFileModel(fileCursorExternal))
        }


        fileCursorInternal = context.contentResolver.query(
            tableInternal,
            column,
            where,
            args,
            "$orderBy DESC"
        )
        while (fileCursorInternal!!.moveToNext()) {
            fetchedFiles.add(setMyFileModel(fileCursorInternal))
        }
    } catch (ex: java.lang.Exception) {
        ex.printStackTrace()
    } finally {
        fileCursorExternal?.close()
        fileCursorInternal?.close()
    }
    
    //fetchedFiles.sortByDescending { it.getMFileDate() } //commented as not working 
    return fetchedFiles
}

Function Where the data from cursor is converted to MyFileModel class object

private fun setMyFileModel(cursor: Cursor): MyFileModel {
    val MyFileModel = MyFileModel()
    if (cursor != null) {
        try {
            MyFileModel.setMFileDate(
                getReadableDate(
                    cursor.getLong(
                        cursor.getColumnIndexOrThrow(
                            MediaStore.Files.FileColumns.DATE_MODIFIED
                        )
                    )
                )
            )

            MyFileModel.setMAbsolute_path(
                cursor.getString(
                    cursor.getColumnIndexOrThrow(
                        MediaStore.MediaColumns.DATA
                    )
                )
            )
            MyFileModel.setMFile_name(
                cursor.getString(
                    cursor.getColumnIndexOrThrow(
                        MediaStore.MediaColumns.TITLE
                    )
                )
            )
            MyFileModel.setMFile_size(
                getReadableSize(
                    cursor.getLong(
                        cursor.getColumnIndexOrThrow(
                            MediaStore.MediaColumns.SIZE
                        )
                    )
                )
            )
            MyFileModel.setFileType(getFileType(MyFileModel.getMAbsolute_path()).name)
            if (MyFileModel.getMAbsolute_path() != null) {
                val file = File(MyFileModel.getMAbsolute_path())
                MyFileModel.setMParent_file(file.parent)
            }
        } catch (ex: Exception) {
            ex.printStackTrace()
        }
    }
    return MyFileModel
}

Function to convert long date to string

 private fun getReadableDate(dateVal: Long): String {
        try {
            var date = dateVal
            date *= 1000L
            return SimpleDateFormat("dd MMM yyyy").format(Date(date))
        } catch (ex: Exception) {
            ex.printStackTrace()
        }
        return ""

    }

Required Output

1- On renaming a file, new file should be created old file should be deleted.

2- New file should have timestamp of old file so that sorting is not disturbed.

What can I try to resolve this?

0

There are 0 best solutions below