基于rsync同步算法的文件同步系统JAVA实现(二)——校验码的生成

作用:

分析差异数据块过程中需要不完整文件各个数据块的两种校验:滚动校验和md4校验,先对完整文件的各个分块依次进行滚动校验,若相同再进行md4校验,若再次相同说明数据块匹配,否则不匹配,在文件中向后移动一个字节形成的新分块进行校验(利用滚动校验的特性可以很快完成)。

核心算法1-滚动校验(参考rsync源码,并作了少量类型修改(unsigned转long)):

弱校验,优点是速度快(但不能保证唯一性),两个校验函数,一种是根据一整个数据块生成校验码,另一种是根据前一个数据块已知的校验码和新的字节信息产生校验码(快)。

源码:

/**
	 * 非递推滚动校验 a simple 32 bit checksum that can be upadted from either end
	 * (inspired by Mark Adler's Adler-32 checksum)
	 * 
	 * @param bs
	 * @param len
	 * @return
	 */
	public static long checkSum_Adler32(byte[] buf, int len) {
		int i;
		long s1, s2;
		// for (i = 0; i < len ; i++) {
		// if (buf[i] < 0) {
		// buf[i] = (byte) -buf[i];
		// }
		// }
		s1 = s2 = 0;
		for (i = 0; i < (len - 4); i += 4) {
			s2 += 4 * (s1 + buf[i]) + 3 * buf[i + 1] + 2 * buf[i + 2]
					+ buf[i + 3];
			s1 += (buf[i + 0] + buf[i + 1] + buf[i + 2] + buf[i + 3]);
		}
		for (; i < len; i++) {
			s1 += (buf[i]);
			s2 += s1;
		}
		return (s1 & 0xffff) + ((s2 & 0xffff) << 16);
	}

	/**
	 * 递推滚动校验 adler32_checksum(X0, ..., Xn), X0, Xn+1 ----> adler32_checksum(X1,
	 * ..., Xn+1) where csum is adler32_checksum(X0, ..., Xn), c1 is X0, c2 is
	 * Xn+1
	 */
	public static long adler32_rolling_checksum(long csum, int len, byte c1,
			byte c2) {
		// if (c1 < 0) {
		// c1 = (byte) -c1;
		// }
		// if (c2 < 0) {
		// c2 = (byte) -c2;
		// }
		long s1, s2;
		s1 = (csum & 0xffff);
		s2 = (csum >> 16);
		s1 -= (c1 - c2);
		s2 -= (len * c1 - s1);
		return (s1 & 0xffff) + ((s2 & 0xffff) << 16);
	}


核心算法2-md4(最好是md5)校验:

强校验,可以保证唯一性,但是速度慢些。

源码略

注意细节:

检验码最终需要转换成字节流,需要给出起始和终止信号。

部分整合源码:

public void writeCheckSumFile(InputStream in,
			OutputStream outStreamCheckSumFile) throws IOException {
		BufferedInputStream inStreamHalfFile = new BufferedInputStream(in);
		byte[] buffer = new byte[BLOCKSIZE];
		int amount = 0;
		while ((amount = inStreamHalfFile.read(buffer)) != -1) {
			sendCheckSumToFile(buffer, outStreamCheckSumFile, amount);
		}
		byte end[] = new byte[24];
		Arrays.fill(end, (byte) -1);
		outStreamCheckSumFile.write(end);
	}

	public void sendCheckSumToFile(byte[] buffer, OutputStream outputStream,
			int amount) throws IOException {
		long sum1 = SumChecking.checkSum_Adler32(buffer, amount);
		byte sum2[] = Md4Checking.mdfour(buffer);
		outputStream.write(DataConvertUtils.long2bytes(sum1));
		outputStream.write(sum2);
	}

	public void readCheckSumFile(String filein) throws IOException {
		BufferedInputStream fileInputStream = new BufferedInputStream(
				new FileInputStream(filein));
		byte[] buffer1 = new byte[8];
		byte[] buffer2 = new byte[16];
		while ((fileInputStream.read(buffer1)) != -1) {
			fileInputStream.read(buffer2);
			System.out.print(DataConvertUtils.bytes2long(buffer1) + ","); //$NON-NLS-1$
			System.out.print(Md4Checking.toHexString(buffer2) + ";"); //$NON-NLS-1$
			System.out.println();
		}
		fileInputStream.close();
	}


发布了35 篇原创文章 · 获赞 61 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/cql342624757/article/details/10241131