在 python 的大型数据集中定位多个文件
Locating multiple files in large dataset in python
我有一个大型图像文件存储库(约 200 万,.jpg
),各个 ID 分布在多个子目录中,我正在尝试在包含 ~ 的列表中找到并复制每个图像这些 ID 的 1,000 个子集。
我对 Python 还是很陌生,所以我的第一个想法是使用 os.walk
遍历每个文件的 1k 子集,以查看子集中是否有任何文件与 id 匹配。这至少在理论上是可行的,但每秒 3-5 张图像的速度似乎非常慢。 运行 通过所有文件一次查找一个 ID 的情况似乎也是如此。
import shutil
import os
import csv
# Wander to Folder, Identify Files
for root, dirs, files in os.walk(ImgFolder):
for file in files:
fileName = ImgFolder + str(file)
# For each file, check dictionary for match
with open(DictFolder, 'r') as data1:
csv_dict_reader = csv.DictReader(data1)
for row in csv.DictReader(data1):
img_id_line = row['id_line']
isIdentified = (img_id_line in fileName) and ('.jpg' in fileName)
# If id_line == file ID, copy file
if isIdentified:
src = fileName + '.jpg'
dst = dstFolder + '.jpg'
shutil.copyfile(src,dst)
else:
continue
我一直在考虑尝试自动执行查询搜索,但数据包含在 NAS 上,我没有简单的方法来为文件编制索引以加快查询速度。我 运行 代码通过的机器是 W10,因此我不能使用 Ubuntu 我收集的 Find 方法在这个任务中要好得多。
如果能加快该过程,我们将不胜感激!
这里有几个脚本可以满足您的需求。
index.py
此脚本使用 pathlib
遍历目录以搜索具有给定扩展名的文件。它将写入一个包含两列的 TSV 文件,文件名和文件路径。
import argparse
from pathlib import Path
def main(args):
for arg, val in vars(args).items():
print(f"{arg} = {val}")
ext = "*." + args.ext
index = {}
with open(args.output, "w") as fh:
for file in Path(args.input).rglob(ext):
index[file.name] = file.resolve()
fh.write(f"{file.name}\t{file.resolve()}\n")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument(
"input",
help="Top level folder which will be recursively "
" searched for files ending with the value "
"provided to `--ext`",
)
p.add_argument("output", help="Output file name for the index tsv file")
p.add_argument(
"--ext",
default="jpg",
help="Extension to search for. Don't include `*` or `.`",
)
main(p.parse_args())
search.py
此脚本会将索引(index.py
的输出)加载到字典中,然后将 CSV 文件加载到字典中,然后对于每个 id_line
它将查找文件名索引并尝试将其复制到输出文件夹。
import argparse
import csv
import shutil
from collections import defaultdict
from pathlib import Path
def main(args):
for arg, val in vars(args).items():
print(f"{arg} = {val}")
if not Path(args.dest).is_dir():
Path(args.dest).mkdir(parents=True)
with open(args.index) as fh:
index = dict(l.strip().split("\t", 1) for l in fh)
print(f"Loaded {len(index):,} records")
csv_dict = defaultdict(list)
with open(args.csv) as fh:
reader = csv.DictReader(fh)
for row in reader:
for (k, v) in row.items():
csv_dict[k].append(v)
print(f"Searching for {len(csv_dict['id_line']):,} files")
copied = 0
for file in csv_dict["id_line"]:
if file in index:
shutil.copy2(index[file], args.dest)
copied += 1
else:
print(f"!! File {file!r} not found in index")
print(f"Copied {copied} files to {args.dest}")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("index", help="Index file from `index.py`")
p.add_argument("csv", help="CSV file with target filenames")
p.add_argument("dest", help="Target folder to copy files to")
main(p.parse_args())
如何运行这个:
python index.py --ext "jpg" "C:\path\to\image\folder" "index.tsv"
python search.py "index.tsv" "targets.csv" "C:\path\to\output\folder"
我会先在 one/two 个文件夹上尝试此操作,以检查它是否具有预期的结果。
在文件名唯一且文件位置不变的假设下,可以创建一个允许在 O(1) 时间复杂度内搜索文件路径的字典。字典创建过程需要一些时间,可以在您的计算机上 pickle 它,因此您只需 运行 它一次。
创建字典的简单脚本:
from pathlib import Path
import pickle
root = Path('path/to/root/folder')
# files extensions to index
extensions = {'.jpg', '.png'}
# iterating over whole `root` directory tree and indexing by file name
image = {file.stem: file for file in root.rglob('*.*') if file.suffix in extensions}
# saving the index on your computer for further use
index_path = Path('path/to/index.pickle')
with index_path.open('wb') as file:
pickle.dump(image, file, pickle.HIGHEST_PROTOCOL)
加载字典的例子:
from pathlib import Path
import pickle
index_path = Path('path/to/index.pickle')
with index_path.open('rb') as file:
image = pickle.load(file)
我有一个大型图像文件存储库(约 200 万,.jpg
),各个 ID 分布在多个子目录中,我正在尝试在包含 ~ 的列表中找到并复制每个图像这些 ID 的 1,000 个子集。
我对 Python 还是很陌生,所以我的第一个想法是使用 os.walk
遍历每个文件的 1k 子集,以查看子集中是否有任何文件与 id 匹配。这至少在理论上是可行的,但每秒 3-5 张图像的速度似乎非常慢。 运行 通过所有文件一次查找一个 ID 的情况似乎也是如此。
import shutil
import os
import csv
# Wander to Folder, Identify Files
for root, dirs, files in os.walk(ImgFolder):
for file in files:
fileName = ImgFolder + str(file)
# For each file, check dictionary for match
with open(DictFolder, 'r') as data1:
csv_dict_reader = csv.DictReader(data1)
for row in csv.DictReader(data1):
img_id_line = row['id_line']
isIdentified = (img_id_line in fileName) and ('.jpg' in fileName)
# If id_line == file ID, copy file
if isIdentified:
src = fileName + '.jpg'
dst = dstFolder + '.jpg'
shutil.copyfile(src,dst)
else:
continue
我一直在考虑尝试自动执行查询搜索,但数据包含在 NAS 上,我没有简单的方法来为文件编制索引以加快查询速度。我 运行 代码通过的机器是 W10,因此我不能使用 Ubuntu 我收集的 Find 方法在这个任务中要好得多。
如果能加快该过程,我们将不胜感激!
这里有几个脚本可以满足您的需求。
index.py
此脚本使用 pathlib
遍历目录以搜索具有给定扩展名的文件。它将写入一个包含两列的 TSV 文件,文件名和文件路径。
import argparse
from pathlib import Path
def main(args):
for arg, val in vars(args).items():
print(f"{arg} = {val}")
ext = "*." + args.ext
index = {}
with open(args.output, "w") as fh:
for file in Path(args.input).rglob(ext):
index[file.name] = file.resolve()
fh.write(f"{file.name}\t{file.resolve()}\n")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument(
"input",
help="Top level folder which will be recursively "
" searched for files ending with the value "
"provided to `--ext`",
)
p.add_argument("output", help="Output file name for the index tsv file")
p.add_argument(
"--ext",
default="jpg",
help="Extension to search for. Don't include `*` or `.`",
)
main(p.parse_args())
search.py
此脚本会将索引(index.py
的输出)加载到字典中,然后将 CSV 文件加载到字典中,然后对于每个 id_line
它将查找文件名索引并尝试将其复制到输出文件夹。
import argparse
import csv
import shutil
from collections import defaultdict
from pathlib import Path
def main(args):
for arg, val in vars(args).items():
print(f"{arg} = {val}")
if not Path(args.dest).is_dir():
Path(args.dest).mkdir(parents=True)
with open(args.index) as fh:
index = dict(l.strip().split("\t", 1) for l in fh)
print(f"Loaded {len(index):,} records")
csv_dict = defaultdict(list)
with open(args.csv) as fh:
reader = csv.DictReader(fh)
for row in reader:
for (k, v) in row.items():
csv_dict[k].append(v)
print(f"Searching for {len(csv_dict['id_line']):,} files")
copied = 0
for file in csv_dict["id_line"]:
if file in index:
shutil.copy2(index[file], args.dest)
copied += 1
else:
print(f"!! File {file!r} not found in index")
print(f"Copied {copied} files to {args.dest}")
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("index", help="Index file from `index.py`")
p.add_argument("csv", help="CSV file with target filenames")
p.add_argument("dest", help="Target folder to copy files to")
main(p.parse_args())
如何运行这个:
python index.py --ext "jpg" "C:\path\to\image\folder" "index.tsv"
python search.py "index.tsv" "targets.csv" "C:\path\to\output\folder"
我会先在 one/two 个文件夹上尝试此操作,以检查它是否具有预期的结果。
在文件名唯一且文件位置不变的假设下,可以创建一个允许在 O(1) 时间复杂度内搜索文件路径的字典。字典创建过程需要一些时间,可以在您的计算机上 pickle 它,因此您只需 运行 它一次。
创建字典的简单脚本:
from pathlib import Path
import pickle
root = Path('path/to/root/folder')
# files extensions to index
extensions = {'.jpg', '.png'}
# iterating over whole `root` directory tree and indexing by file name
image = {file.stem: file for file in root.rglob('*.*') if file.suffix in extensions}
# saving the index on your computer for further use
index_path = Path('path/to/index.pickle')
with index_path.open('wb') as file:
pickle.dump(image, file, pickle.HIGHEST_PROTOCOL)
加载字典的例子:
from pathlib import Path
import pickle
index_path = Path('path/to/index.pickle')
with index_path.open('rb') as file:
image = pickle.load(file)