可以修改深层且复杂的目录结构:可以移动文件(更改前缀),同时可以部分更改文件内容。
我想减少通过网络传输的数据量。
rsync
适用于 4k 大小的数据块(如果我没记错的话)。
我是否可以使用某种串联(tar
类似)来保留有关文件系统结构和属性的元信息,将文件内容从每个下一个文件的多个 4k 字节的偏移量开始,以实现rsync
算法优势?
我想解决的问题是遗漏rsync
:它无法检测文件内容是否更改以及文件在同步之间是否同时移动,以使用目标文件的匹配块来减少数据传输。
答案1
根据您在评论中的建议(实际上应该在您的问题中),这似乎就是您想要的
cd /path/to/directory
tar cf /var/tmp/directory.tar .
rsync -azv /var/tmp/directory.tar remote:/var/tmp/directory.tar
ssh remote 'cd /path/to/destination && tar xf /var/tmp/directory.tar'
directory.tar
两侧都需要足够的空间来存放。
有人问我,这个看似微不足道的解决方案是否可以在从 tar 文件开头添加(或删除)少量内容(例如单个字节)的情况下工作。
希望这个示例能够说明rsync
处理此类情况的能力如何。如果您有远程服务器的等效(证书密钥)登录,则效果最好,这样就无需花时间输入密码。
# Generate some data
dd iflag=fullblock bs=1M count=200 </dev/urandom >200M.dat
# See how long it takes to transfer
time rsync -av 200M.dat remote:
# See how long it takes to transfer "nothing"
time rsync -av 200M.dat remote:
# Generate one byte of data and prepend it to another data file
dd bs=1 count=1 </dev/urandom >1b.dat
cat 1b.dat 200M.dat >200M1b.dat
# Copy the new file across to the original target
time rsync -av 200M1b.dat remote:200M.dat
# Clean up
rm 1b.dat 200M.dat 200M1b.dat
ssh remote rm 200M.dat
如果算法可以处理在数据流开头插入的单个字节,则传输应该只需要几分钟。如果不能,您会期望传输时间与第一次大致相似。
答案2
这是给你的另一个建议。这hrsync
工具我在 GitHub 上发现的,当您重命名文件或在源树的目录之间移动文件时,它似乎非常擅长维护文件的内存。
- 它可以跟踪源树中文件的移动和编辑
- 它是一个 shell 脚本,不需要管理权限即可在源系统上安装,尽管将其放入
/usr/local/bin
确实有优点 - 它要求本地和远程系统都有一个能够处理硬链接的文件系统
- 它无法跟踪文件被重命名的更改,并且被取代(即删除然后重新创建,而不是就地编辑)
例子
hrsync /path/to/directory/ remote:/path/to/destination/
答案3
bash
我找到了仅使用命令行实用程序的解决方案。可以优化解决方案:按大小升序对文件进行排序,并在每个块中放置尽可能多的小文件(这里有背包问题=),但这会是过度设计):
pack.bash
:
#! /usr/bin/env bash
set -e
[[ -d "$1" ]]
[[ -d "$( dirname '$2' )" ]]
BLOB="$2.blob"
FSIZES="$2.sizes"
OFFSET=0
shopt -s globstar
for f in "$1"/* "$1"/**/*
do
if [[ -f "$f" ]]
then
SIZE=$( stat -c %s "$f" )
echo "$SIZE" >> "$FSIZES"
COUNT=$(( ($SIZE + 4096 - 1) / 4096 ))
dd if="$f" of="$BLOB" bs=4096 seek=$OFFSET count=$COUNT conv=notrunc
OFFSET=$(( $COUNT + $OFFSET ))
fi
done
cp --recursive --archive --attributes-only "$1" "$2.dir"
XZ_OPT="-9e --threads=$(( $( nproc ) + 1 ))" tar cpJf "$2.tar.xz" -C "$2.dir" .
rm --recursive "$2.dir"
unpack.bash
:
#! /usr/bin/env bash
set -e
BLOB="$2.blob"
FSIZES="$2.sizes"
[[ -f "$BLOB" ]]
[[ -f "$FSIZES" ]]
mkdir --parents "$1"
[[ ! "$( ls -A '$1' )" ]]
tar xpJf "$2.tar.xz" -C "$1"
SIZES=($( < "$FSIZES" ))
i=0
OFFSET=0
shopt -s globstar
for f in "$1"/* "$1"/**/*
do
if [[ -f "$f" ]]
then
SIZE=${SIZES[i]}
dd if="$BLOB" of="$f" bs=4096 skip=$OFFSET count=$SIZE iflag=count_bytes
OFFSET=$(( $OFFSET + ($SIZE + 4096 - 1) / 4096 ))
i=$(( $i + 1 ))
fi
done