一篇文章搞懂Python的文件路徑操作
前言
如果你要在代碼里讀取一個文件,那么你首先要知道這個文件的路徑。如果只有一個文件,那么很簡單,直接復(fù)制這個文件所在的文件夾路徑及其文件名即可。而在很多情況下,我們會處理大量的文件,這些文件一般都會按一定的規(guī)則存放在一個或幾個文件夾里。本文便是簡單講一下怎么應(yīng)對這種情況,將以Python為例,但其中的理念是通用的。
1 什么是文件路徑
文件路徑簡單地說就是文件的存放位置,它包含具體的盤符號,也就是位于電腦上哪個磁盤分區(qū)、哪個文件夾(目錄)和最終這個文件的名稱+文件類型擴展名。
文件的路徑表示用戶在磁盤上尋找文件時,所歷經(jīng)的文件夾線路;路徑分為絕對路徑和相對路徑;絕對路徑是從根文件夾開始的路徑;相對路徑是從當(dāng)前文件夾開始的路徑。
1.1 絕對路徑
不同操作系統(tǒng)下絕對路徑的表現(xiàn)形式是不一樣的,以Windows系統(tǒng)為例,一個文件的路徑可能是這樣的:
D:\files\data\ndvi.tif
其中:
D:\
:表示根文件夾,是文件所在的盤符,即D
盤。D:\files\data
:表示文件所在的文件夾的路徑,即D
盤的files
文件夾的子文件夾data
。ndvi.tif
:表示文件名,其中ndvi
是基本名,用來標(biāo)識這個文件;tif
是擴展名,用來反映文件的類型,二者用.
分開。
Linux和MacOS下的絕對路徑和Windows系統(tǒng)不同,主要區(qū)別如下:
- 根文件夾不同,Windows的根文件夾是盤符,如D:\、C:\;而在Linux和MacOS中,根文件夾是/,你可以理解為所有的文件都在一個盤下,自然不需要用C、D這樣的字符去區(qū)分了。
- 分隔符不同,在Windows 上,路徑書寫使用倒斜杠\作為文件夾之間的分隔符。但在MacOS和Linux上,使用正斜杠/作為它們的路徑分隔符。
- 大小寫區(qū)分不同,文件夾名稱和文件名在Windows和MacOS上是不區(qū)分大小寫的,但在Linux上是區(qū)分大小寫的。
附加卷的路徑:
附加卷,諸如DVD驅(qū)動器或USB閃存驅(qū)動器,在不同的操作系統(tǒng)上顯示也不同。在Windows上,它們表示為新的、帶字符的根驅(qū)動器。諸如
D:\
或E:\
。在MacOS上,它們表示為新的文件夾,在/Volumes
文件夾下。在Linux上,它們表示為新的文件夾,在/mnt
文件夾下。
1.2 相對路徑
相對路徑是指以當(dāng)前工作目錄為參照基礎(chǔ),鏈接到目標(biāo)文件資源(或文件夾)的路徑。
相對路徑的表示符號如下:
- 以
./
開頭,代表當(dāng)前目錄和文件目錄在同一個目錄里,./
也可以省略不寫; - 以
../
開頭:向上走一級,代表目標(biāo)文件在當(dāng)前文件所在的上一級目錄; - 以
../../
開頭:向上走兩級,代表父級的父級目錄,也就是上上級目錄,再說明白點,就是上一級目錄的上一級目錄; - 以
/
開頭,代表根目錄。
相對路徑使用示例:
2 Python對路徑的操作
2.1 在Python中怎么表示文件路徑
在Python中,一般使用字符串存儲文件路徑。但需要注意的是,字符反斜杠\
在Python中表示轉(zhuǎn)義字符。因此,在表示W(wǎng)indows系統(tǒng)下的文件路徑(Windows系統(tǒng)的分隔符是\
)時需注意以下要點:
- 以路徑D:\files\data\ndvi.tif為例;
- 在字符串前加個字符r,表示該字符串為原始字符串,會完全忽略所有的轉(zhuǎn)義字符。例如,r"D:\files\data\ndvi.tif";
- 對轉(zhuǎn)義字符進行轉(zhuǎn)義,例如,"D:\\files\\data\\ndvi.tif";
- 將分隔符替換為/,是的,在Windows系統(tǒng)下,將分隔符替換為/Python也能正確識別。例如,"D:/files/data/ndvi.tif"。
Linux和MacOS下,直接將路徑放到單引號或者雙引號里就行。
2.2 創(chuàng)建新文件夾
可以用os.mkdir()
函數(shù)創(chuàng)建新文件夾(目錄),使用os.path.isdir()
函數(shù)判斷一個路徑是不是文件夾,如下所示:
import os path = "D:/files/data" if os.path.isdir(path): os.mkdir(path)
需要注意的是,os.mkdir()
函數(shù)只能創(chuàng)建單級目錄。如上面的代碼所示,只有"D:/files"
目錄存在,才能在其下創(chuàng)建data
目錄。要想創(chuàng)建多級目錄,則要使用os.makedirs()
函數(shù),例如:
import os path = "D:/files/data" if os.path.isdir(path): os.makedirs(path)
os.listdir()
方法用于返回指定的文件夾包含的文件或文件夾的名字的列表,只支持在 Unix, Windows 下使用,例如:
>>> import os >>> os.listdir("D:/files/data") ['ndvi.tif', 'ndvi_2023_01.tif']
2.3 拼接和拆分文件夾
os.path.join()
函數(shù)用于路徑拼接文件路徑,可以傳入多個路徑,它會根據(jù)操作系統(tǒng)的不同自動確定分隔符。
>>> import os >>> os.path.join(r'D:\files\data', 'ndvi_2023_01.tif') 'D:\\files\\data\\ndvi_2023_01.tif' >>> os.path.join('D:/files/data', 'ndvi_2023_01.tif') 'D:/files/data\\ndvi_2023_01.tif' >>> os.path.join('./data', 'ndvi_2023_01.tif') './data\\ndvi_2023_01.tif' >>> os.path.join('files', 'data', 'ndvi_2023_01.tif') 'files\\data\\ndvi_2023_01.tif'
os.path.split()
函數(shù)可以把一個路徑拆分為兩部分,后一部分總是最后級別的目錄或文件名。os.path.splitext()
函數(shù)同樣可以把一個路徑拆分為兩部分,后一部分總是最后的文件擴展名。
>>> os.path.split("D:/files/data/ndvi.tif") ('D:/files/data', 'ndvi.tif') >>> os.path.split("D:/files/data") ('D:/files', 'data') >>> os.path.splitext("D:/files/data/ndvi.tif") ('D:/files/data/ndvi', '.tif') >>> os.path.splitext("D:/files/data") ('D:/files/data', '')
此外,os.path.basename()
函數(shù)用于獲取路徑最后的文件名或文件夾名,os.path.dirname()
函數(shù)用于去掉最后的文件名或文件夾名,返回余下的文件夾路徑。
>>> os.path.basename("D:/files/data/ndvi.tif") 'ndvi.tif' >>> os.path.basename("D:/files/data") 'data' >>> os.path.dirname("D:/files/data/ndvi.tif") 'D:/files/data' >>> os.path.dirname("D:/files/data") 'D:/files'
2.4 處理絕對路徑和相對路徑
os.path
模塊提供了一些函數(shù),返回一個相對路徑的絕對路徑,以及檢查給定的路徑是否為絕對路徑。
- os.getcwd():獲取當(dāng)前工作目錄;
- os.path.abspath(path):返回參數(shù)的絕對路徑的字符串,以當(dāng)前工作目錄為基準(zhǔn)。這是將相對路徑轉(zhuǎn)換為絕對路徑的簡便方法;
- os.path.isabs(path):如果參數(shù)是一個絕對路徑,就返回True,如果參數(shù)是一個相對路徑,就返回 False;
- os.path.relpath(path, start):將返回從start路徑到path的相對路徑的字符串。如果沒有提供start,就使用當(dāng)前工作目錄作為開始路徑。
代碼示例:
>>> os.getcwd() 'C:\\Python34' >>> os.path.abspath('.') 'C:\\Python34' >>> os.path.abspath('.\\Scripts') 'C:\\Python34\\Scripts' >>> os.path.isabs('.') False >>> os.path.isabs(os.path.abspath('.')) True >>> os.path.relpath('C:\\Windows', 'C:\\') 'Windows' >>> os.path.relpath('C:\\Windows', 'C:\\spam\\eggs') '..\\..\\Windows'
2.4 使用glob查找文件夾或文件
glob
模塊用來查找文件目錄和文件,并將搜索的到的結(jié)果返回到一個列表中。
在使用glob
模塊之前,需要先了解一下它的三個通配符,即*
、?
和[]
,其具體含義如下:
*
:代表0個或多個字符;?
:代表一個字符;[]
:匹配指定范圍內(nèi)的字符,如[0-9]
匹配數(shù)字;[a-c]
匹配字母a
、b
或c
,不區(qū)分大小寫;[12a]
匹配字母1
、2
或a
。
下面通過一個例子詳細講一下這三個通配符怎么使用,假如你有如下所示的目錄結(jié)構(gòu):
+-- D:/
| +-- data1
| | +-- readme.md
| | +-- ndvi.tif
| | +-- buliding.tif
| +-- data2
| | +-- ndvi.tif
| | +-- water.tif
| +-- picture
| | +-- mm.tif
|
假如你要查找data1
下的所有以.tif
結(jié)尾的文件,你可以這樣寫:
>>> from glob import glob >>> glob('D:/data1/*.tif') ['D:/data1/ndvi.tif', 'D:/data1/buliding.tif']
假如你要查找data
開頭的目錄下的所有名為ndvi.tif
的文件,你可以這樣寫:
>>> glob('D:/data*/ndvi.tif') ['D:/data1/ndvi.tif', 'D:/data2/ndvi.tif'] >>> glob('D:/data?/ndvi.tif') ['D:/data1/ndvi.tif', 'D:/data2/ndvi.tif'] >>> glob('D:/data[1-2]/ndvi.tif') ['D:/data1/ndvi.tif', 'D:/data2/ndvi.tif']
3 多個文件的路徑操作示例
在數(shù)據(jù)處理中,很多時候我們都會有這樣的要求,處理多個文件,并且要按照一定的順序。最常見的就是按照時間順序排列各個文件的路徑,比如按年、月、日等,下面詳細介紹幾個例子。
3.1 年尺度數(shù)據(jù)
假如你有如下目錄結(jié)構(gòu):
+-- D:/
| +-- data
| | +-- 2000.tif
| | +-- 2001.tif
... ... ... ... ...
| | +-- 2019.tif
| | +-- 2020.tif
|
如果你要讀取data
目錄下2000-2020年所有文件的路徑(按時間順序排列),你可以這樣寫:
import os from glob import glob # glob會自動排序這些文件路徑,排序的規(guī)則為文件名 paths = glob('D:/data/*.tif*') # 或者這樣寫,可以指定開始和結(jié)束年份 paths = [] root_dir = 'D:/data' start_year, end_year = 2000, 2020 for year in range(start_year, end_year): path = os.path.join(root_dir, f'{year}.tif') paths.append(path)
3.2 月尺度數(shù)據(jù)
假如你有如下目錄結(jié)構(gòu):
+-- D:/
| +-- data
| | +-- 200001.tif
| | +-- 200002.tif
... ... ... ... ...
| | +-- 200012.tif
| | +-- 200101.tif
... ... ... ... ...
| | +-- 202012.tif
|
假如你要讀取data
目錄下某一年或某幾年所有月的tif
數(shù)據(jù),你可以這樣寫:
import os from glob import glob # 讀取2015年所有月的數(shù)據(jù) year = 2015 paths = glob(f'D:/data/{year}*.tif*') # 讀取2015-2020年所有月的數(shù)據(jù) paths = [] root_dir = 'D:/data' start_year, end_year = 2015, 2020 for year in range(start_year, end_year): path += os.path.join(root_dir, f'{year}*.tif')
假如你要讀取data
目錄特定年在某個季節(jié)的tif
數(shù)據(jù),你可以這樣寫:
import os from glob import glob # 假設(shè)一年的冬季為當(dāng)年的1月、2月以及上一年的12月 season_months = {'spring': ['03', '04', '05'], 'summer': ['06', '07', '08'], 'autumn': ['09', '10', '11'], 'winter': ['01', '02']} paths = [] root_dir = 'D:/data' season = 'spring' years = [2014, 2015, 2016] for year in years: months = season_months[season] for month in months: path = os.path.join(root_dir, 'f{year}{month}.tif') assert path paths.append(path) if season == 'winter': path = os.path.join(root_dir, 'f{year-1}{12}.tif') assert path paths.append(path)
3.3 日尺度數(shù)據(jù)
假如你有如下目錄結(jié)構(gòu),如文件名中的1982001
表示數(shù)據(jù)拍攝時間為1982年的第1天。
./ndvi/AVH13C1.A1982001.N07.005.2017161044559.NDVI.tif —— 1982001 —— 1982年第1天
./ndvi/AVH13C1.A1982002.N07.005.2017161050433.NDVI.tif —— 1982002 —— 1982年第2天
./ndvi/AVH13C1.A1982003.N07.005.2017161052408.NDVI.tif —— 1982003 —— 1982年第3天
./ndvi/AVH13C1.A1982004.N07.005.2017161054145.NDVI.tif —— 1982004 —— 1982年第4天
./ndvi/AVH13C1.A1982005.N07.005.2017161055856.NDVI.tif —— 1982005 —— 1982年第5天
./ndvi/AVH13C1.A1982006.N07.005.2017161061328.NDVI.tif —— 1982006 —— 1982年第6天
假如你要讀取某一年年某一月中所有天的數(shù)據(jù)的路徑,你可以這樣寫:
import os import calendar from glob import glob from datetime import datetime def get_year_month_paths(root_path, year, month): '''獲取某年某月所有NDVI文件的路徑''' paths = [] # 用于glob函數(shù)的通配符字符串,可視作文件名模板 fmt = '*{}{:03}*.tif' # 計算該年該月共有多少天 month_days = calendar.monthrange(year, month)[1] # 計算該年該月的第一天是一年中的第幾天 month_start_day = (datetime(year, month, 1) - datetime(year, 1, 1)).days + 1 for i in range(month_days): day_num = month_start_day + i month_day_path = glob(os.path.join(root_path, fmt.format(year, day_num))) if not month_day_path: print('{}年{}月的數(shù)據(jù)缺失,編號為{}{:03}'.format(year, month, year, day_num)) paths += month_day_path return paths
3.4 文件的時間順序隱藏在文件內(nèi)
有些文件你下載時的默認(rèn)文件名是一堆無意義的字符,而你知道這些文件里存儲的有時間信息,所以就沒有對這些文件一一命名。當(dāng)你要用時你就會發(fā)現(xiàn)很麻煩,要按時間順序讀取這些文件,靠文件名沒法做到,而文件太多,一個個打開看一下時間再重命名又太慢了。這樣只能在代碼里一個個打開文件,讀取其時間,并依據(jù)這些時間對文件的路徑進行排序。這種情況常見于.nc
或.hdf
格式的數(shù)據(jù),其內(nèi)部會存儲時間信息,而有些網(wǎng)站下載文件時文件名有沒有時間信息。
假如你有如下目錄結(jié)構(gòu):
./RH/ked.nc
./RH/mmm.nc
./RH/dii.nc
./RH/jkd.nc
./RH/zex.nc
./RH/xyz.nc
每個nc
文件下都有一個名為time
的變量,類型為數(shù)組,用于記錄時間。以ERA5數(shù)據(jù)為例,其小時尺度的數(shù)據(jù)記錄的當(dāng)前時間距格里尼治時間1900-01-01-00:00
的小時數(shù),若要將其轉(zhuǎn)為東八區(qū)的字符串格式的時間,可以這么做:
import datetime import netCDF4 as nc ds = nc.Dataset('./RH/ked.nc') time = ds['time'][...].data origin_date = datetime.datetime(1900, 1, 1, 0, 0) start_date = origin_date+datetime.timedelta(hours=int(times[0])+8) start_date = start_date.strftime('%Y-%m-%d-%H')
而如果我們不需要對這些nc
文件重命名,只是要在代碼里對這些文件的路徑進行排序,只需要這么做:
from glob import glob nc_paths = glob(os.path.join('./RH', '*.nc')) times = [] for nc_path in nc_paths: # 提取各站點的溫度 ds = nc.Dataset(nc_path) time = ds.variables['time'] times.append(int(time[0].data)) _, nc_paths = (list(t) for t in zip(*sorted(zip(times, nc_paths))))
最后,對文件路徑進行操作的可能性有無數(shù)種,掌握這些基本知識,學(xué)會舉一反三,多動手嘗試,只有這樣在數(shù)據(jù)處理中才能游刃有余。
總結(jié)
到此這篇關(guān)于Python文件路徑操作的文章就介紹到這了,更多相關(guān)Python文件路徑操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python中網(wǎng)絡(luò)請求中Retry策略實現(xiàn)方式
這篇文章主要介紹了Python中網(wǎng)絡(luò)請求中Retry策略實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-06-06Pytorch 如何實現(xiàn)LSTM時間序列預(yù)測
本文主要基于Pytorch深度學(xué)習(xí)框架,實現(xiàn)LSTM神經(jīng)網(wǎng)絡(luò)模型,用于時間序列的預(yù)測2021-05-05python操作excel的方法(xlsxwriter包的使用)
這篇文章主要為大家詳細介紹了python操作excel的方法,xlsxwriter包的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06python GUI庫圖形界面開發(fā)之PyQt5輸入對話框QInputDialog詳細使用方法與實例
這篇文章主要介紹了python GUI庫圖形界面開發(fā)之PyQt5輸入對話框QInputDialog詳細使用方法與實例,需要的朋友可以參考下2020-02-02pandas的object對象轉(zhuǎn)時間對象的方法
下面小編就為大家分享一篇pandas的object對象轉(zhuǎn)時間對象的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04python使用paramiko實現(xiàn)ssh的功能詳解
這篇文章主要介紹了python使用paramiko實現(xiàn)ssh的功能詳解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03