我有一个高度结构化的分层目录,其中包含多个文件,需要将这些文件移动到平面结构中并同时重命名。必须将原始路径和名称与新路径和名称一起记录,并最终加载到数据库中。最后,每个重命名的文件必须获得唯一的,不可取的(IE:加密或散列)文件名。当重命名的文件移动到新的目录结构中时,我还想限制每个目录中的文件数,因此每个目录都会创建一个序列号作为其名称,然后将文件加载到其中,直到达到最大值在使用下一个序列号作为名称滚动到新目录之前,已达到文件数(例如:255)。
是否有工具/软件可以做到这一点?我做了一些初步的研究,没有提出以下标准:
答案 0 :(得分:1)
我过去使用过几个Bash脚本,用于将手工制作的文件存储库迁移到散列存储库,以便从Web应用程序(主要是PHP应用程序)进行访问和管理。在这些存储库中,对文件名进行哈希处理(以避免与具有相同内容/名称的文件发生冲突),并且文件均匀分布(以确定的方式或随机分布),以便出于性能原因使每个文件的数量保持较低。以下是一个完整的例子:
#!/bin/bash
MAXFILESPERDIR=500
TARGETROOTDIR="./newrepository"
RANDOMDISTRIBUTION=1
if [ -d "$1" ]; then
LOGFILE=$(basename $0).$(date +"_%Y%m%d_%H%M").${$}.log
SQLFILE=$(basename $0).$(date +"_%Y%m%d_%H%M").${$}.sql
SOURCEDIR="$1"
TOTALSOURCEFILES=$(find "$1" -type f | wc -l)
let "TOTALTARGETDIRS=$TOTALSOURCEFILES / $MAXFILESPERDIR"
PADLENTARGETDIRS=${#TOTALTARGETDIRS}
PADLENTARGETFILE=${#TOTALSOURCEFILES}
echo "We will create $TOTALTARGETDIRS directories to hold $MAXFILESPERDIR files per directory."
if [ "$RANDOMDISTRIBUTION" == "1" ] ; then
echo "We will rename and distribute each file randomly."
else
echo "We will rename and distribute each file uniformly."
fi
echo "Do you want to continue?"
select choice in yes no ; do
if [ "$choice" == "yes" ] ; then
COUNTER=1
find "$1" -type f | while read SOURCEFILE ; do {
CHECKSUMFILE=$(sha1sum "$SOURCEFILE" | cut -d " " -f 1)
CHECKSUMNAME=$(echo "$SOURCEFILE" | sha1sum | cut -d " " -f 1)
DETERMINISTICNONCE=$(printf "%0${PADLENTARGETFILE}d\n" $COUNTER)
if [ "$RANDOMDISTRIBUTION" == "1" ] ; then
PROBABILISTICNONCE=$(let "XX=$RANDOM % $TOTALTARGETDIRS + 1" ; printf "%0${PADLENTARGETDIRS}d\n" $XX;)
else
PROBABILISTICNONCE=$(let "XX=$COUNTER % $TOTALTARGETDIRS + 1" ; printf "%0${PADLENTARGETDIRS}d\n" $XX;)
fi
FILEDATE=$(stat -c %z "$SOURCEFILE" | cut -d "." -f 1)
FILESIZE=$(stat -c %s "$SOURCEFILE")
echo "Source file $SOURCEFILE" >> $LOGFILE
echo "Target file $TARGETROOTDIR/$PROBABILISTICNONCE/$PROBABILISTICNONCE$CHECKSUMFILE$DETERMINISTICNONCE" >> $LOGFILE
echo "INSERT INTO files (Filename, Location, Checksum, CDate, Size) VALUES ('$PROBABILISTICNONCE$CHECKSUMFILE$DETERMINISTICNONCE', '$PROBABILISTICNONCE', '$CHECKSUMFILE', '$FILEDATE', $FILESIZE);" >> $SQLFILE
mkdir -p $TARGETROOTDIR/$PROBABILISTICNONCE
cp -v "$SOURCEFILE" $TARGETROOTDIR/$PROBABILISTICNONCE/$PROBABILISTICNONCE$CHECKSUMFILE$DETERMINISTICNONCE
let "COUNTER+=1"
} ; done
echo "Done."
echo
break
fi
if [ "$choice" == "no" ] ; then
echo
echo "Operation cancelled"
echo
break
fi
done
else
echo
echo "Missing source directory"
echo
fi
只需从新存储库的根目录运行它。您可以配置它修改第一个变量:MAXFILESPERDIR定义每个目录存储多少个文件,TARGETROOTDIR是创建第一级目录的第一级目录的名称(它只使用两个级别,第一个是真正的单个目录root)和RANDOMDISTRIBUTION定义文件是否随机分布(它可能看起来不均匀,特别是对于小运行)或确定性(仅计数)。
它如何运作(仅供参考,以防这不是你想要的,但也许你可以得到一些想法):
如果将RANDOMDISTRIBUTION设置为1并多次运行该脚本,您将获得源文件的副本,因为每次运行时每个文件都会获得不同的目标文件名/路径。如果将RANDOMDISTRIBUTION设置为其他内容,则每次运行脚本时,文件都将以相同的方式重命名(对于相同的文件集,如果添加或删除文件,它们将获得不同的名称/路径)。
使用随机值+ hash +计数器的目的是确保我们可以处理重复项(由于计数器不会发生冲突),同时仍然随机分配文件(对于足够长的运行,这将均匀地分配文件)。
此外,生成的文件名的前缀也是目录的名称,因此如果您有文件名和目录名长度,则可以计算目录名称(以防万一您不存储该目录名称)在您的数据库表中。)
最后,这是一个一次性的迁移脚本,它并没有真正写在同一组文件上定期执行。