2021年5月12日 星期三

PowerShell 修改檔案的 建立時間/修改時間/存取時間 程式

PowerShell 修改檔案的 建立時間/修改時間/存取時間 程式

tags: 部落格文章


新文章有更易用的方式詳細請看這篇https://charlottehong.blogspot.com/2022/02/powershell.html







關於檔案的 修改時間 和 存取時間有什麼差別可以看這篇站內文
https://charlottehong.blogspot.com/2021/05/win10.html

字串格式和日期格式怎麼互轉可以參考這一邊
https://charlottehong.blogspot.com/2021/05/powershell-string-datetime.html

修改檔案時間

其實也就是讀檔然後修改而已。

$Date = New-Object DateTime(2021, 12, 31, 18, 30, 59);
$FileName = "Z:\a.txt"

$file = Get-Item $FileName
$file.CreationTime   = $Date; #建立日期
$file.LastWriteTime  = $Date; #修改日期
$file.LastAccessTime = $Date; #存取日期

懶人包程式

這是封裝好的程式,要使用的話按下 Win+X 在按 A 會跳出一個可以輸入的視窗,把底下全部貼上。

# 產生日期格式
function NewDatetime {
    param (
        [string]$date = "",
        [string]$formatType = "yyyy-MM-dd HH:mm:ss"
    )
    # 未輸入日期則返回當前時間
    if ([string]::IsNullOrEmpty($date)) {
        $newDate = (Get-Date)
    }
    # 格式化日期
    else {
        $newDate = [DateTime]::ParseExact(
            $date.Trim(), $formatType,
            [CultureInfo]::InvariantCulture
        )
    }
    return $newDate
}
# 讀取檔案日期
function readFileDate {
    param (
        [string]$FileName
    )
    $file = Get-Item $FileName;
    Write-Host "建立日期" $file.CreationTime;     #建立日期
    Write-Host "修改日期" $file.LastWriteTime;    #修改日期
    Write-Host "存取日期" $file.LastAccessTime;   #存取日期
}
# 改變檔案日期
function ChangeFileDate {
    param (
        # [Parameter(Mandatory, Position=0)]
        [Parameter(Mandatory, Position=0)]
            [string]$FileName,
        [Parameter(ParameterSetName="setDetail")]
            [datetime]$CreationTime,
        [Parameter(ParameterSetName="setDetail")]
            [datetime]$LastWriteTime,
        [Parameter(ParameterSetName="setDetail")]
            [datetime]$LastAccessTime,
        [Parameter(ParameterSetName="setAll")]
            [datetime]$AllTime,
        [switch]$Preview
    )
    if ($AllTime) {
        $CreationTime   = $AllTime;
        $LastWriteTime  = $AllTime;
        $LastAccessTime = $AllTime;
    }

    $file = Get-Item $FileName
    if ($Preview) {
        Write-Host "[$FileName]"
        Write-Host "  " $file.CreationTime "-->" $CreationTime
        Write-Host "  " $file.LastWriteTime "-->" $LastWriteTime
        Write-Host  "  " $file.LastAccessTime "-->" $LastAccessTime
    } else {
        if ($CreationTime) {
            $file.CreationTime = $CreationTime; #建立日期
        } if ($LastWriteTime) {
            $file.LastWriteTime = $LastWriteTime; #修改日期
        } if ($LastAccessTime) {
            $file.LastAccessTime = $LastAccessTime; #存取日期
        }
    }
}

全部貼上去之後按 Enter 就可以開始使用了



使用方法

在使用前先執行這兩行代碼(記得要按Ennter輸入)
會自動切換到桌面,並建一個檔案等一下要範例用

cd ~\Desktop
"" >> a.txt

好了就可以開始拉

查詢檔案日期

readFileDate a.txt

修改全部日期

ChangeFileDate "a.txt" -AllTime "2021-5-10 23:59:59"

改完之後按 ↑ 兩次選到剛剛執行查詢的代碼,可以看一下有沒有改變

修改單一日期

如果只想改變其中一個而已的話,改法像這樣

# 只改變建立日期
ChangeFileDate "a.txt" -CreationTime "2021-5-11 23:59:59"
# 只改變修改日期
ChangeFileDate "a.txt" -LastWriteTime "2021-5-12 23:59:59"
# 只改變存取日期
ChangeFileDate "a.txt" -LastAccessTime "2021-5-13 23:59:59"

如果要改其中兩個,可以打兩行也可以把後面的部分串起來就好

# 改任意兩個(這3組可以隨便串)
ChangeFileDate "a.txt" -CreationTime "2021-5-14 23:59:59" -LastAccessTime "2021-5-15 23:59:59"

預覽

如果你怕改錯的話可以在加上 -Preview 預覽一下
加上這個之後就不會變更日期,只會看到預覽的訊息

ChangeFileDate "a.txt" -AllTime "2021-5-10 23:59:59" -Preview

PowerShell 字串String 與 日期Datetime 格式轉換

PowerShell 字串String 與 日期Datetime 格式轉換

tags: 部落格文章

字串轉時間

建構子

直接用建構子是最簡單的

New-Object DateTime(2021, 5, 12, 22, 29, 30)


進階自訂格式

核心的程式長這樣

[DateTime]::ParseExact("13.May.2017", "dd.MMM.yyyy",[CultureInfo]::InvariantCulture)

這樣簡單一行就能夠格式化字串到日期了

強化一下寫好的副程式是這樣的

function newDatetime {
    param (
        [string]$date = "",
        [string]$formatType = "yyyy-MM-dd HH:mm:ss"
    )
    # 未輸入日期則返回當前時間
    if ([string]::IsNullOrEmpty($date)) {
        $newDate = (Get-Date)
    }
    # 格式化日期
    else {
        $newDate = [DateTime]::ParseExact(
            $date.Trim(), $formatType,
            [CultureInfo]::InvariantCulture
        )
    }
    return $newDate
}

使用的話直接這就可以用了

newDatetime "2000-01-01 12:00:00"

要自訂格式的話,後面空格多補一個參數

newDatetime "13.May.2017" "dd.MMM.yyyy"



日期轉字串

再來是把日期轉出來到字串,這個就比較容易

方式1

直接轉成字串即可

(Get-Date).ToString("yyyy-MM-dd HH:mm:ss")

方式2

陣列轉換

'{0:yyyy-MM-dd HH:mm:ss}' -f (Get-Date)

Win10 【修改日期】和【存取日期】有什麼差別不同處

Win10 【修改日期】和【存取日期】有什麼差別不同處

tags: 部落格文章

以前就一直很好奇這兩個東西到底有什麼不同,因為邏輯很奇怪,有比對過的人應該都會滿頭問號XDD

今天寫程式要改日期,不得不把他們弄懂只好乖乖爬文了,遺憾的目前能檢索到的中文資料居然沒一篇講清楚的,來補一下這個中文資源吧~



建立日期 CreationTime

這個應該很好懂就是這一份檔案什麼時產出來的,這個永遠都不會變動。

以下情況才會發生改變

  1. 複製的時候的時候,產生一份新檔案(修改日期會保留)
  2. 上傳到雲端在下載回來的檔案屬於新建檔案(通常修改會滯後於新建,時間差就是下載的時間)
  3. RAR解壓出來屬於複製檔案



修改日期 LastWriteTime

指的是對檔案的內容的變更,這個應該沒什麼疑念。
只要有修改內容就會更新時間了。



存取日期 LastAccessTime

這個才是最難理解的,看名字就覺得開啟檔案也算吧,很遺憾不一定會馬上反應。

這不是非常反邏輯不是就寫著存取了嗎?

事實上因為每次開檔就更改存取日期非常消耗系統效能,預設微軟把她關了,對就是給關了,但並不是完全關閉而是智能保護。

這個智能保護的邏輯可能隨著Windows系統更新被優化,我的當前版本是Win10 20H2

怎麼解除保護狀態呢,很簡單直接打開記事本給他修改一下後保存,就解除了。

當保護解除時,以下動作都會變動存取日期

  1. 查看檔案內容 (寫到緩存還沒更新到硬碟)
  2. 檔案內容修改
  3. 檔名修改
  4. 移動檔案
  5. 複製檔案

基本上就是名如其實,有存取都會紀錄

至於怎查看緩存的內容可以直接打下面這行指令

# 查看檔案存取日期
(Get-Item "Z:\a.txt").LastAccessTime


如何取消能保護可以執行這行指令
(沒需求的話別做死浪費硬碟效能)

# 關閉智能保護
# fsutil behavior set disablelastaccess 0

另外有一種情況開檔會變更”存取日期”,但不會變更”修改日期”,有些Excle或Word裡面是有帶腳本的的打開的瞬間腳本執行就會變更”存取日期”和”修改日期”,關閉檔案後因為沒變更軟體會自動把”修改日期”改回原本的日期。以至於打開又關閉一看,奇怪怎麼存取日期變了。



從日期判斷檔案有過什麼操作

實際做一些操作來試試看變化吧

更改檔名(未解除保護)

沒有變動

建立日期 2021/5/12 下午 05:32:57
修改日期 2021/5/12 下午 05:32:57
存取日期 2021/5/12 下午 05:32:57

移動檔案(未解除保護)

沒有變動

建立日期 2021/5/12 下午 05:27:29
修改日期 2021/5/12 下午 05:27:29
存取日期 2021/5/12 下午 05:27:29

複製檔案

建立與存取日期會更新

建立日期 2021/5/12 下午 05:26:32
修改日期 2021/5/15 下午 12:34:56
存取日期 2021/5/12 下午 05:26:32

修改內容

修改會滯後於修改(這段時間是你開檔到存檔的時間差)

建立日期 2021/5/12 下午 05:59:07
修改日期 2021/5/12 下午 05:59:36
存取日期 2021/5/12 下午 05:59:38




參考

2021年5月2日 星期日

chrome瀏覽器 開某些網站會 LAG 改用 EDGE 就好了怎麼處理

chrome瀏覽器 開某些網站會 LAG 改用 EDGE 就好了怎麼處理

這個問題我一直很好奇怎麼會這樣,我開Youtube、FaceBook都可以感受到。

尤其是舊版的FB卡的不要不要的,甚至是HackMD這種筆記網頁也會,後來在巴哈看到有人在討論的意外地解決了。

解決辦法

來這個頁面

chrome://flags/#use-angle

把Choose ANGLE graphics backend這個選項改成 D3D9 可以改善。
具體原理也不太清楚,貌似是和顯示卡有關吧~

個人是直接改用 Edge 棄用 chrome 了

2021年4月24日 星期六

PowerShell 如何輸出 不帶BOM的 UTF-8 檔案

PowerShell 如何輸出 不帶BOM的 UTF-8 檔案

本文的說明都是針對 PowerShell 5.1 版本,從6版本開始就沒這個問題了,直接 Out-File 就是 UTF8 了。

這個問題很坑,現在版本的Windows10還在用舊版的 PowerShell 5.1 導致輸出UTF8檔案的時候是帶有BOM的。

個人認為最好的解決辦法是直接更新到 PowerShell7.0 就直接什麼問題都沒有了,預設輸出就是不帶BOM的UTF8。



解決方案1 - ASCII

簡單粗暴的的方法,直接寫入 ASCII 就好了。
不能寫中文,但可以記下來應急的時候很好用。

$FileContent = "only english content"
$dstPath = [Environment]::GetFolderPath("Desktop")
$FileContent | Out-File -Encoding ASCII "$dstPath\utf8.txt"

解決方案2 - WriteAllLines

這個方法就不會出問題了,不過是從記憶體一次寫入大小有限。

$FileContent = "中文UTF8內容"
$dstPath = [Environment]::GetFolderPath("Desktop")
$Enc = (New-Object System.Text.UTF8Encoding $False)
[System.IO.File]::WriteAllLines("$dstPath\utf8.txt", $FileContent, $Enc);

解決方案3 - Out-FileUtf8NoBom

這個函式比較能從根本解決問題

載入很簡單,直接打這行就可以把方法載入了

irm https://gist.github.com/mklement0/8689b9b5123a9ba11df7214f82a673be/raw/Out-FileUtf8NoBom.ps1 | iex

再來使用方法和原本的 Out-File 差不多 (不過原作者並沒有實現全部的接口)

$FileContent = "中文UTF8內容"
$dstPath = [Environment]::GetFolderPath("Desktop")
$FileContent | Out-FileUtf8NoBom $dstPath\utf8.txt

這樣就能簡單生成一個不帶BOM的UTF8文件了。

原作者:https://gist.github.com/mklement0/8689b9b5123a9ba11df7214f82a673be


 

如何安裝 Out-FileUtf8NoBom 到電腦上

上面的指令關掉之後副程式就沒了,每次都要重新載入,如果想要用久的安裝到電腦上,可以使用下面指令。

# 調整權限
Set-ExecutionPolicy RemoteSigned -scope CurrentUser

# 創建初始化腳本檔
if (!(Test-Path -Path $PROFILE )) { New-Item -Type File -Path $PROFILE -Force }

# 從gist載入函式
irm https://gist.github.com/mklement0/8689b9b5123a9ba11df7214f82a673be/raw/Out-FileUtf8NoBom.ps1 | iex

# 把函式寫入腳本檔
"`nfunction Out-FileUtf8NoBom {`n${function:Out-FileUtf8NoBom}`n}" | Out-FileUtf8NoBom -Append $PROFILE

這樣就永久安裝到電腦了,隨時都可以用 Out-FileUtf8NoBom 函式了


其他編碼轉換

其他編碼的轉法可以參考這裡的查詢方法

# 直接存取只有預設與UTF8 (可以按TAB一個一個查)
 [Text.Encoding]::Default
[Text.Encoding]::UTF8

# 用名稱查詢
[Text.Encoding]::GetEncoding('UTF-8')
[Text.Encoding]::GetEncoding('BIG5')
[Text.Encoding]::GetEncoding('Shift_JIS')

# 用編號查詢
[Text.Encoding]::GetEncoding(65001)
[Text.Encoding]::GetEncoding(950)
[Text.Encoding]::GetEncoding(932)

實際使用時像這樣

# 編碼
$Enc_Default = [Text.Encoding]::Default
$Enc_UTF8_BOM = [Text.Encoding]::GetEncoding(65001)
$Enc_UTF8 = New-Object System.Text.UTF8Encoding $False
$Enc_BIG5 = [Text.Encoding]::GetEncoding(950)
$Enc_SIFT = [Text.Encoding]::GetEncoding(932)

# 讀寫檔案
$Encoding = $Enc_UTF8
[System.IO.File]::ReadAllLines($Path, $Content, $Encoding);
[System.IO.File]::WriteAllLines($Path, $Content, $Encoding);


UTF8 比較特別要用別的寫法否則會變成帶有BOM的檔案,或者是直接在WriteAllLines() 函數上省略最後面的 $Encoding 參數也可以。



參考

2021年4月22日 星期四

PowerShell 如何把資料夾特定檔案 轉換至 UTF8 編碼

PowerShell 如何把資料夾特定檔案 轉換至 UTF8 編碼

tags: 部落格文章

會寫這篇是因為正在學得教程是中國來的 Eclipse 載入之後直接給我亂碼,要一個檔案慢慢添加個別轉換有夠煩的~

程序也搞了好久,先說 PowerShell5.1 不好用建議乖乖去載 PowerShell7.0來用。

順帶一提要解決 PowerShell5.1 用Out-File輸出帶BOM的問題,把編碼改成 ASCII 或是留空都不要打預設就好了。

本篇範例是用 PowerShell7.0 如果你的環境只能用5.1版,上面提到的在自己測試一下。

更新PS7

懶人包打指令,會自動跳出安裝檔一路下一步到底就好

iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI -Quiet"

或是下面官網手動下載,拖下去之後就有載點了
https://github.com/PowerShell/PowerShell

檔案轉換核心代碼

最關鍵的地方就是這裡啦,有點長我用個變數拆兩段,他是可以合體的。(合體之後記得前面整串$ct要括號起來)

    # 要被轉換的檔案位置與編碼
    $En1=GBK
    $F1='z:\file.txt'
    # 轉換後的檔案位置與編碼
    $En2=UTF8
    $F2='z:\file_UTF8.txt'

    $ct = Get-Content -Encoding $En1 $F1
    $ct | Out-File -Encoding $En2 $F2

這樣執行就可以轉換了,F2可以設置成跟F1 一樣就變成同一份檔案直接轉,但是非常不建議這樣做。不小心連續執行兩次檔案就毀了。

檔案編碼似乎是不能查的,我不知道為什麼用VScode這種近代的編輯器是怎麼偵測的,估計是演算法吧?因為也會有錯的時候所以肯定不是寫在檔案上。

寫成一行的範例

這邊還是要再提一次,當前版本的Windows只有內建的PS版本只到5還沒更新到PS7,PS7要自己手動下載,並且手動打開不會更新到系統上。

範例是把一個在Z:\的檔案 File.java,由 GBK 轉換到 UTF8

(Get-Content -Encoding GBK 'Z:\File.java') | Out-File 'Z:\File_UTF8.java'

要是跳出下面訊息
Get-Content : 無法繫結 ‘Encoding’ 參數。無法將 “GBK” 值轉換為 “Microsoft.PowerShell.Commands.FileSystemCmdletProv
單純只是舊版沒支援GBK而已,去升級吧XD。

批量轉換

這個大概是大家最關心的部分,整個把整資料夾裡面有 java 的全部都抓出來轉換到另一個目錄。

這次第一版半成品,那時候沒查到怎麼處理字串建資料夾的方式有點多此一舉。舊版本就不砍了,有需要功能完善的版本從底下連結自取。

## 初版
function  CovertFileEncoding_basic ($F1, $En1, $En2, $F2){
    $ct = (Get-Content -Encoding $En1 $F1)
    $ct | Out-File -Encoding $En2 -FilePath $F2
}
function  CovertFileEncoding ($F1, $En1, $En2, $F2, $tempPath){
    if (!(Test-Path -Path $tempPath)) {
        Write-Warning "暫存資料夾不存在"
    }
    $F2=$tempPath+$F2
    mkdir $F2 | Out-Null
    Remove-Item $F2
    CovertFileEncoding_basic $F1 $En1 $En2 $F2
}

# 轉換FilePath目錄下的所有java檔案,到tempPath目錄
function CovertDirEncoding($FilePath, $tempPath, $go=0) {
    $list = Get-ChildItem -Path $FilePath -Recurse -Filter *.java
    $listN = Get-ChildItem -Path $FilePath -Recurse -Filter *.java -Name
    for ($i = 0; $i -lt $list.Count; $i++) {
        $F1=$list[$i].FullName
        $F2=$listN[$i]
        if ($go -eq 0) {
            $F2
        } elseif ($go -eq 1){
            CovertFileEncoding $F1 "GBK" "UTF8" $F2 $tempPath
        }
    }
}

$FilePath = 'C:\Users\hunan\Desktop\JavaWeb\25\hotel2\src\'
$tempPath = 'Z:\temp\'
CovertDirEncoding $FilePath $tempPath

完整版

GitGub: https://github.com/hunandy14/DirCoverToUtf8

最底下的部分

# 路徑
$FilePath = "Z:\SourceCode\31"
$TempPath = $PSScriptRoot
cd $PSScriptRoot

預設只要更改 $FilePath 即可

變數 $TempPath 是複製的目的地,預設會自動建立在批次檔旁邊。
最後第三行單純只避免寫代碼的時候出事把目錄調到當前

詳細說明以後再寫,覺得八成還會再大動版本,還沒想到怎麼輸入排除檔案跟轉換檔案的方式。有寫應該會先更新在 github 上。