2012-06-06 18 views
1

我有一个高度结构化的分层目录,其中包含需要移动到平面结构并同时重命名的多个文件。原始路径和名称必须与新路径和名称一起记录,并最终加载到数据库中。最后,每个重命名的文件都必须得到一个唯一的,不可猜测的(IE:加密或散列)文件名。当重命名的文件移动到新的目录结构中时,我也想限制每个目录中的文件数量,因此每个目录都将创建一个连续的数字作为其名称,然后文件将被加载到最大在滚动到具有下一个连续编号名称的新目录之前,已达到文件数(例如:255)。批量重命名/移动/散列文件

有没有这样的工具/软件?我做了一些初步的研究,并没有想出了以下标准:

  • 批量重命名&拷贝到替代(扁平化)的结构
  • 散列/加密文件名,并确保其唯一性
  • 顺序名称的文件夹和限制文件数
  • 日志中的每个文件的原始名称和路径,以及新的(加密)的名称和路径

回答

1

我有我已经在过去使用到m几个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是创建第一级目录的第一级目录的名称(它只使用两个级别,第一个是真正的单一目录根),RANDOMDISTRIBUTION定义文件是否随机分布(它可能看起来不均匀,特别是对于小批量运行)或确定性(只是计数)。

它是如何工作(仅供参考,以防万一这是不是你在找什么,但也许你可以得到一些想法):

  1. 计数的源文件。
  2. 计算将创建多少个目标目录。
  3. 请求确认。
  4. 对于每个文件:
    • 计算文件内容的SHA1哈希值。
    • 创建确定性随机数。
    • 创建概率随机数(如果RANDOMDISTRIBUTION为1,否则只是一个计数器)。
    • 获取大小和修改日期。
    • 将随机值的值与散列和计数器组合以获得新文件名(路径将是随机值)。
    • 记录源和目标完整路径。
    • 创建并记录SQL插入查询。
    • 创建目标目录(如果它不存在)。
    • 复制文件。 (你可以移动它,如果你想,但我玩的很安全)。
  5. 完成

如果设置RANDOMDISTRIBUTION为1并运行该脚本几次,你会得到你的源文件的副本,因为每个文件将每次运行得到不同的目标文件名/路径它。如果将RANDOMDISTRIBUTION设置为其他内容,则每次运行脚本时,文件都将以相同的方式重命名(对于相同的文件集,如果添加或删除文件,它们将得到不同的名称/路径)。

使用随机值+散列+计数器的目的是确保我们可以处理重复(不会因计数器而发生碰撞),同时仍然随机分发文件(对于足够长的运行,这将分配文件均匀)。

此外,生成文件名的前缀也是该目录的名称,以便如果您有文件名和目录名称长度,则可以计算目录名称(以防万一您不存储在你的数据库表中)。

最后,这是一次性迁移脚本,它并没有真正写入通过同一组文件定期执行。