程式目的:依圖片寬度,複製至不同目錄。
問題:
出錯1→PermissionError?(windows之目錄已設定為完全控制)
出錯2→Permission denied?(永遠無法複製檔案至目錄b1。(但b2、b3鐵定ok))
網上看了很多網頁,多半說是絕對路徑的問題,但是我是寫絕對路徑沒錯吧?
先謝謝大大指導。m(__)m
from PIL import Image as im
import os, shutil as s
o = 'c:\\temp\\p454bu'
os.chdir(o)
for n in range(1, 4):
k = "b"+str(n)
if os.path.exists(k):
s.rmtree(k)
os.makedirs(k, exist_ok=True)
# 出錯1:PermissionError: [WinError 5] 存取被拒。: 'b2' ← 有時是b3
a, b, c = os.path.join(o, "b1"), os.path.join(o, "b2"), os.path.join(o, "b3")
for n in os.listdir(o): # listdir return relative path
f = im.open(n)
if f.size[0] < 500:
# s.copy(n, b1) # shutil need absolute path
s.copy(n, a) # 出錯2:[Errno 13] Permission denied: 'b1' ←永遠是b1出錯
elif f.size[0] < 1000:
s.copy(n, b)
else:
s.copy(n, c)
from PIL import Image as im
import os, shutil as s
o = 'c:\\temp\\p454bu'
#刪除目錄
def delete_folder(dir_path):
s.rmtree(dir_path, ignore_errors=True)
print(f"\tDeleted '{dir_path}' successfully")
for n in [1,2,3]: delete_folder(f"{o}\\b{n}")
#創建目錄,如果目錄不存在
def mkdir_if_not_exists(out_dir):
if not os.path.exists(out_dir):
os.makedirs(out_dir)
print(f"\t{out_dir} Created!")
else:
print(f"\t{out_dir} Existed!")
a,b,c = f"{o}\\b1",f"{o}\\b2",f"{o}\\b3"
mkdir_if_not_exists(a)
mkdir_if_not_exists(b)
mkdir_if_not_exists(c)
for n in os.listdir(o):
print(n)
if '.png' in n or '.jpg' in n:
tmp_file_src = o+"\\"+n
f = im.open(tmp_file_src)
if f.size[0] < 500:
s.copy(tmp_file_src, a)
elif f.size[0] >= 500 and f.size[0] < 1000:
s.copy(tmp_file_src, b)
else: # f.size[0] >=1000
s.copy(tmp_file_src, c)
直接給你一個範例參考,你遇到的問題可能是:
建議多利用 Python 現有的函式/函式庫不要自己造輪子,比如說如果你要取得某資料夾裡面所有的圖片列表,照你原本的寫法,是包括資料夾b1,b2,b3都會列在n裡面,這時你用im.open()去處理它,不報錯才奇怪,我用的是最簡單的判斷n裡面是否有包含'.png'或'.jpg',確定是圖檔的才作判斷圖片尺寸並依width分資料夾複制,
在google搜尋'python img list in a folder'應該能找到不少現成的範例,不過那離題了在此打住。
另外你在寫分資料夾複制那邊的if ... elif ... 也有邏輯 bug,想想看~ if fs<500 ... elif fs <1000 ...
請問 fs若為 300 是不是<500 跟 <1000 都成立?
做資料夾刪改
的操作時,建議避免以下(但不限於)類型的程式占用欲刪改的資料夾、子資料夾或子檔案:
Windows 檔案總管
之類的 檔案管理程式
。Win-Cmd
PowerShell
等 Terminal
或 Console
類的程式或相關 script。例如開啟資料夾
、開啟檔案
、切換工作目錄(working directory)至相關資料夾
等操作,有可能在檔案系統上造成安全性鎖定衝突之類的現象。
在 file-open
操作時,建議:
file-open
時的操作。file-open
的習慣。以降低在檔案系統上發生安全性鎖定衝突之類的現象。
建議避免或最小化切換工作目錄(working directory)的操作, 尤其是 常會忘記身在何處的人
、 在有資料夾刪改的操作時
、 函式或模組等程式具工作目錄依存性時
等情境下。
或必要時,至少,處理完必要程序後馬上切換回安全的目錄。
根據這裡的敘述,if
陳述式的確是由上而下,執行首個運算式為真值的套組(suite)後,就跳離 if
陳述式了。
所以我認為你的 if f.size[0] < 500: ## ...
陳述式的流程設計邏輯沒問題。
除非在麻煩的環境如平行處理等情境下,不然我認為是沒必要採用 ccutmis 大提出的嚴謹用法;因為多個判斷就是多消耗系統時間。
其他的就請看後續的「小改版」程式碼內容。
至於 Permission-whatever 原因我是懶得分析~就提供上述建議給你參考而已。
下面是基於你的程式碼的小改版:
## Tested @[Python 3.10];
from PIL import Image as im
import os, shutil as s
o = 'c:\\temp\\p454bu'
os.chdir(o)
for n in range(1, 4):
k = "b"+str(n)
if os.path.exists(k):
s.rmtree(k)
os.makedirs(k, exist_ok=True)
a, b, c = os.path.join(o, "b1"), os.path.join(o, "b2"), os.path.join(o, "b3")
#for n in os.listdir(o): # listdir return relative path
for n in [
## os.listdir() 會列出所有物件的名稱: 不論是檔案(file)或目錄(directory)等物件,
## 所以用 os.path.isfile() 過濾出檔案的名稱;
id for id in os.listdir(o)
if os.path.isfile(os.path.join(o, id))
]:
#f = im.open(n)
try: ## 用 try-except 敘述處理「無法判斷圖片格式的檔案」等例外情況;
## 用 with 敘述以在讀取尺寸後自動關閉檔案,避免鎖死等意外;
with im.open(n) as f:
w = f.size[0] ## get-img-width;
except Exception as exc:
print('□ Exception:[' + type(exc).__name__ + ']:', exc)
continue
if w < 500:
# s.copy(n, b1) # shutil need absolute path
#s.copy(n, 'b1') ## 這裡要用'字串' (或許是你一時寫錯?);
## 我試過 shutil.copy() 能用相對路徑,沒限定需使用絕對路徑;
s.copy(n, a)
elif w < 1000:
s.copy(n, b)
else:
s.copy(n, c)
範例小改版: 絕對路徑/相對路徑
切換版:
## Tested @[Python 3.10];
from PIL import Image as im
import os, shutil as s
## https://docs.python.org/zh-tw/3/tutorial/introduction.html?highlight=raw#strings
o = os.path.abspath(r'c:\temp\p454bu')
os.chdir(o)
myDirs = list() ## list for directory-path (or directory-name);
for n in range(3):
## https://docs.python.org/zh-tw/3/tutorial/inputoutput.html#tut-f-strings
k = f'b{n+1}'
if os.path.exists(k): s.rmtree(k)
os.makedirs(k, exist_ok=True)
match 0: ## aSwitch:(0|1): 切換用相對路徑(@0)或絕對路徑(@1);
case 0: myDirs.append(k)
case 1: myDirs.append(os.path.join(o, k))
for n, e in enumerate(myDirs): print(n, e, type(e))
for n in [
id for id in os.listdir(o)
if os.path.isfile(os.path.join(o, id))
]:
try:
with im.open(n) as f: w = f.size[0]
except Exception as exc:
print(f'□ Exception:[{type(exc).__name__}]: {exc}')
continue
if w < 500 : s.copy(n, myDirs[0])
elif w < 1000 : s.copy(n, myDirs[1])
else : s.copy(n, myDirs[2])
##
另,在「iT邦幫忙」的語法高亮 Markdown 的自動判斷常錯誤,建議用下面方式指定語言:
#### this is a markdown script;
#### next block is a python script;
```py
print('hello, world')
```
我只是拿以前寫別的程式的經驗來引用,因為它是 if ... elif ... else ... 這麼寫會有邏輯錯誤。你想想三選一的分支如果 w是一也符合二也符合,那它執行哪個分支才是正確的?
if w < 500 : ...
elif w < 1000 : ...
else : ...
如果他是:
if w < 500 : ...
if w < 1000 : ...
這樣就沒問題,每個 if 是各自獨立的。
@ccutmis:
在這段中:
if w < 500 : print('RunA')
elif w < 1000 : print('RunB')
else : print('RunC')
w = 10
時,的確會使 w < 500
、 w < 1000
這兩項為真。
但因為其 if-elif-else
執行流程的關係,僅會執行 w < 500
的內容。
這樣就算「w = 10
時會使 w < 500
、 w < 1000
這兩項為真」也不會有問題啊。
對我來說,只要程式流程、結果符合邏輯與要求就好了,我不懂去探討「那它執行哪個分支才是正確的?」有啥意義?
倒是感覺你忽視 Python 的 if-elif-else
陳述式之執行流程的依序性。
還是其實 Python 的 if-elif-else
陳述式的執行流程是亂序?(大驚!)
有啥意義?
其實這也只是個人編程習慣,畢竟嚴謹一點比凡事差不多好… 當然也可能是我被舊習慣誤導了,就像有的人廻圈堅持要用for i in range()嘛^^"
@ccutmis: 我也贊同嚴謹是好事~
就算是舊習慣也好,只要不會搞到畫地自限等詭異情況就好~
(我就有很多我自己都覺得詭異的習慣~)
畢竟在最佳化與除錯等作業之間,常常就是在嚴謹的思慮間徘徊、取捨。
每人的思慮、習慣不同,會有各種誤解很正常;我也偶爾會失智而一時各種神奇誤解~ XD
我看這邊討論的還挺有趣的,分享一下我的看法,兩種寫法結果截然不同:
sample code 1:
w=30
a=b=c=1
if w < 500 : a=2
elif w < 1000 : b=2
else : c=3
print(a, b, c)
sample code 2:
w=30
a=b=1
if w < 500 : a=2
if w < 1000 : b=2
print(a, b)
sample code 1的狀況其實就等於以下狀況,以前看別人寫的C常常有這種寫法,可以少判斷一個w >= 500
,是一種偷懶的寫法,但會嚴重增加程式碼閱讀困難所以不推薦。
if w < 500 : a=2
elif w >= 500 and w < 1000 : b=2
else : c=3
@ alien663:
為何要拿 C 的壞習慣與 Python 正常語法比較? 那是個人程式設計上的問題吧??
可以少判斷一個w >= 500,是一種偷懶的寫法,但會嚴重增加程式碼閱讀困難所以不推薦。
這反倒讓我閱讀困難……
因為我會用上 if-elif-else
語法,必然會考慮一整個流程。
用上兩個獨立的 if
,就會把兩個流程分別考慮。
在 if-elif-else
流程上做多餘判斷,這反而讓我困惑……
我想是我解釋不明確讓你誤會了,我指的是sample 1的寫法讓人閱讀困難,事實上我個人更偏好sample 1的等價寫法,跟你是一樣的觀點。
至於sample 2,變數b的結果可是被修改到了,跟sample 1的邏輯完全不一樣。
我個人不會說sample 2的寫法就是錯,雖然少見,但說不定需求就長那樣子。
我以前看別人寫的C語言有很多精妙設計,為了少宣告一個變數或是少判斷一個條件等等的,會有很多閱讀上會增加難度的寫法,只是作為一個分享而已。我認為現今如果不是在嵌入式系統上的話,簡單、清楚又明瞭的程式碼反而會是更重要的事情。
@alien663: 閱讀困難狀況是看個人啦,畢竟各人有各人的身心靈等各方面上的習慣;我也只是說我困擾的感想。
說到 C 語言的精妙, 我只怕不懂裝懂而亂用的同事(不是同事就沒差~ XD), 一整個恐怖。
我也喜歡簡單、清楚又明瞭的程式碼;但我,個人而言,比較看重程式註解的內容。
因為很多時候,我都會有「至少請他喵的讓我知道你到底想做啥好嗎?」這種感嘆~
You can double-check directory permissions, run as administrator if needed, and adjust your wordle unlimited code to handle potential permission issues gracefully.