准备工作(可选,mac环境)
安装Homebrew
安装python3
设置默认python
(.bashrc文件在文件中添加 alias python="python3"即可)
安装python编辑器Sublime3
用Python检查资源文件是否Valid
有时候编译打包时会报资源文件格式错误。比如某个jpg的文件被重命名为png, 然后放到了图片资源目录下,就可能导致编译失败。
为此写了一个Python脚本来自动检测此类错误。
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
import os
import imghdr
PATH = input("Dir:").strip()
pngString = "png"
for path, dirs, files in os.walk(PATH):
for filename in files:
fullpath = os.path.join(path, filename)
try:
format = imghdr.what(fullpath)
print("image path: " + fullpath)
print("image format: " + str(format))
except Exception as e:
print(f"Error processing file: {fullpath}")
print(f"Error message: {str(e)}")
PATH 是要检测的路径名,walk方法会遍历改PATH下的所有文件,包括子文件夹下的文件。然后检测真实的格式(format)(即使重命名过也没事)。最后如果格式不是png,就会打印出文件名。
使用方法:
- 文本编辑器复制这段代码,保存为.py结尾的文件。
- 改成自己的检测路径
- 在命令行中运行,比如
python /Users/apple/Desktop/imgcheck.py
即可
批量重命名图片并复制到drawable文件夹
带注释的脚本:
# -*- coding: utf-8 -*-
import os
import shutil
# 从哪里拷贝图片
pathFrom = input("move drawable from:").strip()
# 拷贝到哪个文件夹 比如项目下的drawable—xhdpi文件夹
pathTo = input("move drawable to:").strip()
# 要批量重命名的字符串 一般是@2x。也是需要复制的图片的标志,因为如果不需要重命名的话,就直接复制 不需要脚本了。
iDentifyString = input("iDentifyString:").strip()
for path, dirs, files in os.walk(pathFrom):
for fileName in files:
print(fileName)
if iDentifyString.lower() in fileName.lower():
fromFullpath = os.path.join(path, fileName)
# 去掉@2x 替换不合法方字符 改成小写
newFileName = fileName.replace(
iDentifyString, "").replace("-", "_").lower()
print(newFileName)
toFullPath = os.path.join(pathTo, newFileName)
shutil.copyfile(fromFullpath, toFullPath)
使用场景:UI给了切图,但是是按IOS命名的。@2x @3x 这样。安卓只需要拿@2x的图片,并去掉@2x这几个字符。
批量重命名
windows系统没有提供批量重命名的工具,就自己用写了个脚本:
import re
# 从哪里拷贝文件
pathFrom = input("move file from:").strip()
# 拷贝到哪个文件夹 目前是新建rename文件夹
pathTo = os.path.join(pathFrom, "rename")
if not os.path.exists(pathTo):
os.makedirs(pathTo)
# 要批量重命名的字符串
iDentifyString = "_sign"
for path, dirs, files in os.walk(pathFrom):
for fileName in files:
# 没有重命名的文件也复制
newFileName = fileName
fromFullpath = os.path.join(path, fileName)
if iDentifyString.lower() in fileName.lower():
# 去掉iDentifyString
newFileName = fileName.replace(
iDentifyString, "")
newFileName = re.sub(r'(_(\d{1,3}))+_', r'_', newFileName)
print(newFileName)
toFullPath = os.path.join(pathTo, newFileName)
#如果不是rename文件夹下的文件
if not "rename" in fromFullpath:
shutil.copyfile(fromFullpath, toFullPath)
这样,文件名 appName_1.1.1_111_1_qq_sign.apk 就会重命名为 appName_1.1.1_qq.apk
bug解决
使用zipFile压缩文件时, 发现中文的文件名会乱码, 搜索无果,就自己调试, 最后发现zipfile.py中执行_encodeFilenameFlags方法时, 没有执行utf-8编码.
(具体原因没时间去探究,就通过改源码的方式解决了, 毕竟就我的日常操作而言,执行UTF-8编码是没有问题的)
原来的代码:
def _encodeFilenameFlags(self):
if isinstance(self.filename, unicode):
try:
return self.filename.encode('ascii'), self.flag_bits
except UnicodeEncodeError:
return self.filename.encode('utf-8'), self.flag_bits | 0x800
else:
return self.filename, self.flag_bits
修改后代码:
def _encodeFilenameFlags(self):
if isinstance(self.filename, unicode):
try:
return self.filename.encode('ascii'), self.flag_bits
except UnicodeEncodeError:
return self.filename.encode('utf-8'), self.flag_bits | 0x800
else:
return self.filename.encode('utf-8'), self.flag_bits | 0x800
- Tip
老版本的python比如3.9下载的opencv库,使用新版本python如3.12时会找不到,需要重新下载
分文件夹脚本
(某文件夹有两千多张照片, 翻页会卡, 就平均分割成多个文件夹,方便查看):
# -*- coding: utf-8 -*-
import os
import imghdr
import shutil
currentIndex = 0
currentPath = ""
# 从哪里拷贝
currentFolderIndex = 0
pathFrom = input("move from:").strip().lstrip('\"').rstrip('\"').lstrip('\'').rstrip('\'')
# 拷贝到哪个文件夹
pathTo = input("move to:").strip().lstrip('\"').rstrip('\"').lstrip('\'').rstrip('\'')
print(pathFrom)
currentPath = os.path.join(pathTo, str(currentFolderIndex))
os.mkdir(currentPath)
for path, dirs, files in os.walk(pathFrom):
for fileName in files:
print(fileName)
if currentIndex >= 100:
currentIndex = 0
currentFolderIndex += 1
currentPath = os.path.join(pathTo, str(currentFolderIndex))
os.mkdir(currentPath)
fromFullpath = os.path.join(path, fileName)
# print(newFileName)
toFullPath = os.path.join(currentPath, fileName)
shutil.copyfile(fromFullpath, toFullPath)
currentIndex += 1
帮算法组写的整理数据的功能(文件输入 字符串搜索 遍历数组)
# -*- coding: utf-8 -*-
import os
import imghdr
import shutil
def read_file_as_str(file_path):
if not os.path.isfile(file_path):
raise TypeError(file_path + " does not exist")
all_the_text = open(file_path).read()
return all_the_text
errorDataFileLocation = input("errorDataFileLocation:").strip().lstrip('\"').rstrip('\"').lstrip('\'').rstrip('\'')
errorDataListStr = read_file_as_str(errorDataFileLocation)
dataSourceFileLocation = input("dataSourceFileLocation:").strip().lstrip('\"').rstrip('\"').lstrip('\'').rstrip('\'')
dataSourceStr = read_file_as_str(dataSourceFileLocation)
dataSource = dataSourceStr.replace(".pts", "").replace("\n", "").split("./");
print("items start")
for item in dataSource:
if item in errorDataListStr:
errorDataListStr = errorDataListStr.replace(item, "")
print("./" + item + ".jpg")
print("items end")
print("errorDataListStr")
print(errorDataListStr.strip())
动态执行command命令
合成2个视频
# -*- coding: utf-8 -*-
import os
import subprocess
tag = input("Tag:").strip()
command = 'ffmpeg -i /Users/xx/Desktop/Demo_RenderSDK/{Tag}_AE.mov -i /Users/xx/Desktop/Demo_RenderSDK/{Tag}_Demo.mp4 -filter_complex "[0:v]pad=iw*2:ih[a];[a][1:v]overlay=w:0" /Users/xx/Desktop/对比2/{Tag}左AE右Demo.mp4'.format(Tag = tag)
subprocess.call(command, shell=True)
合成3个视频
# -*- coding: utf-8 -*-
import os
import subprocess
tag = input("Tag:").strip()
command = 'ffmpeg -i /Users/atlasv-hongjunmin/Desktop/material/videos/{Tag}_V1.mp4 -i /Users/atlasv-hongjunmin/Desktop/material/videos/{Tag}_V2.mp4 -i /Users/atlasv-hongjunmin/Desktop/material/videos/{Tag}_V3.mp4 -filter_complex "[0:v]pad=iw*3:ih[a];[a][1:v]overlay=w[b];[b][2:v]overlay=w*2:0" /Users/atlasv-hongjunmin/Desktop/material/对比/{Tag}_左V1中V2右V3.mp4'.format(Tag = tag)
subprocess.call(command, shell=True)
取视频第一帧(如果要缩略图,在图片文件名前加-s 320*280这样的参数)
# -*- coding: utf-8 -*-
import os
import subprocess
path = input("videoPath:").strip()
filepath,fullflname = os.path.split(path)
command = 'ffmpeg -i {PATH} -vframes 1 -update 1 -f image2 {FILEPATH}/1.jpg'.format(PATH = path,FILEPATH = filepath)
print("command: " + command)
subprocess.call(command, shell=True)
Tip:
jsonpath性能差但是至少能用,jsonpath-ng遇到稍微大一点的json就崩溃了,报错之多令人费解,jsonpath支持正则表达,jsonpath-ng 不支持
直接使用Python自带的json模块来操作json的话,示例代码如下:
#以只读模式打开Json文件
with open('xxx.json', 'r') as templetesFile:
templetesJson = json.load(templetesFile)
#Python里字典默认用单引号包裹key和value(双引号也支持),但json格式里的key需要是双引号,所以需要下面的语句来转化成json格式。最后一个参数设置为False,就不会将中文转换成ascii码
msg = json.dumps(targetJson, indent=4, ensure_ascii=False)
- 引号嵌套
在f-string中,如果在大括号内使用引号,则大括号内引号必须与字符串引号不同,否则会报错。
#内双引号,外单引号
f'python is {"good"}'
# 内单引号,外双引号
f"python is {'good'}"
Python判断实例的类型:
How to check if type of a variable is string? [duplicate]
multiprocessing.Manager.dict()的线程和进程安全,是指
在单个字典操作的级别上锁定,而不是整块代码。所以类似 if key not in dict, dict[key] = value
这种,就需要全局lock的require lock操作
另外,manager.dict()读取比较慢,写操作更慢,网上有解决的trick,比如在普通字典里写好值后调用manager.dict() 的update方法,或者用其他方式实现多线程和多进程共享的字典
- Pandas相关
Pandas对cvs迭代并修改数据保存:
def file2dataframe(filename: str, sheet_name=0) -> pd.DataFrame:
"""文件转pandas的DataFrame"""
if filename.endswith('csv'):
return pd.read_csv(filename)
elif filename.endswith('xlsx'):
return pd.read_excel(filename, sheet_name=sheet_name)
else:
raise ValueError('不支持的文件格式')
# 赋值后会是传值,即新开辟一块内存,所以要直接赋值: https://blog.csdn.net/qq_16555103/article/details/115185138
df = df.where(df.notnull(), None)
self.bar = tqdm(total=len(df), desc='替换url 迭代行')
for index, row in df.iterrows():
df.loc[index, 'XXX'] = self._replaceUrl(row['XXX'])
self.bar.update(1)
self.bar.close()
month = datetime.datetime.now().month
day = datetime.datetime.now().day
df.to_csv(f"{month}_{day}.csv")
- 处理音频数据
- 音量处理,可以实现音量归一化等
import glob
import os
from pydub import AudioSegment
#convert to mp3 128 bits
sound = AudioSegment.from_file("input-file.aac")
sound.export("output-file.mp3", format="mp3", bitrate="128k")
#sound.max_dBFS shows how far below the limit the highest sample is (in dB)
sound = AudioSegment.from_file("output.mp3", format="mp3")
max_gain_without_distortion = -1 * sound.max_dBFS
#increase volume by"max_gain_without_distortion" dB
from pydub.playback import play
song = AudioSegment.from_mp3("output-file.mp3")
louder_song = song + max_gain_without_distortion
#save louder song
louder_song.export("output.mp3", format='mp3')
def printError(tag, doTraceback=False):
errorMsg = {}
_, value, tb = sys.exc_info()
tbs = traceback.extract_tb(tb)
if len(tbs) > 0:
errorMsg['Location'] = f'File {tbs[-1].filename}, line {tbs[-1].lineno}, in {tbs[-1].name}'
errorMsg['Message'] = f'{value.__class__.__name__}: {str(value)}'
errorMsg['tag'] = f'{tag}'
if doTraceback:
errorMsg['Stack'] = f'{traceback.format_exc()}'
print(f'errorMsg: {errorMsg}')
def getDb(path, format):
try:
sound = AudioSegment.from_file(path, format=format)
print(f"path{path} \n duration{sound.duration_seconds}")
max = sound.max
dBFS = sound.dBFS
max_dBFS = sound.max_dBFS
result = {"sound": sound, "path": path, "max": max, "dBFS": dBFS, "max_dBFS": max_dBFS}
#print(result)
return result
except Exception as e:
printError(path)
@multitasking.task
def toSameDb(pathStandard, formatStandard, pathTomodify, formatToModify, targetPath):
try:
dbStandard = getDb(pathStandard, formatStandard)
dbTomodify = getDb(pathTomodify, formatToModify)
change_in_dBFS = -1 * (dbTomodify["dBFS"] - dbStandard["dBFS"])
targetSong = dbTomodify["sound"].apply_gain(change_in_dBFS)
targetSong.export(targetPath, format=formatToModify)
except Exception as e:
printError(pathTomodify)
def toSameDbs(pathStandard, formatStandard, dirTomodify, formatToModify, targetDir):
resourceFiles = os.listdir(dirTomodify)
progressBar = tqdm(total=len(resourceFiles), desc='音频统一音量')
for fileName in resourceFiles:
#print(f"fileName:{fileName} basename:{os.path.basename(fileName)}")
toSameDb(pathStandard, formatStandard, os.path.join(dirTomodify, fileName), formatToModify, os.path.join(targetDir, fileName))
progressBar.update(1)
multitasking.wait_for_tasks()
progressBar.close()
OSS
python罗列oss文件(方法1会把目录当File, 方法2只会过滤文件夹)Shell
在shell脚本里调用第三方命令或脚本后查看命令的返回值
ret_code=$? # 执行执行的结果需要马上获取。一般0表示success
echo "command ret_code $ret_code"