From 1cf473929a5001f9f6aff5ae27e9bd73e97df1b0 Mon Sep 17 00:00:00 2001 From: bigbeats <70423253+bigbeats@users.noreply.github.com> Date: Wed, 9 Dec 2020 06:43:08 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=97=A0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重新提交一次commits --- gitcontroltool/Blob.java | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/gitcontroltool/Blob.java b/gitcontroltool/Blob.java index 5c08277..514dd64 100644 --- a/gitcontroltool/Blob.java +++ b/gitcontroltool/Blob.java @@ -1,26 +1,26 @@ -/* һ⣺Ҫblob -@1. value洢ӶӦkey-value - step1 ڹ½һfile󣬲дļݣ̨롢дһеļ - step2 ΪfileΪļhashֵ +/* 任务一的理解:主要是针对blob对象 +@1. 给定value,向存储中添加对应的key-value + step1 在工作区新建一个file对象,并写入文件内容(控制台输入、或者是写入一个已有的文件) + step2 为这个file对象重命名为《文件的hash值》并保存 -@2. keyҵõӦvalueֵ - ȡļhashֵͿԵõļݣʱļhashֵkeyļݾvalue +@2. 给定key,查找得到对应的value值 + 如果读取《文件的hash值》就可以得到文件内容,此时《文件的hash值》就是key,文件内容就是value。 */ package gitcontroltool; import java.io.*; -// װBlob࣬԰blob֣һȡļݣ +// 封装Blob类,类中属性包含blob对象的名字,一个输入流变量(用来读取具体的文件内容) public class Blob { - private String name; // blob - FileInputStream input; // - public Blob(String filename) throws Exception { // blobĹ췽ԭļݲ䣬һļΪhashorigin's valueblob - Hash s = new Hash(filename,true); // step1.һеľļɶӦhashֵ - this.name = s.getSha(); // step2.Ϊǰblobhashֵ - this.input = new FileInputStream(filename); // step3.ɵǰľļɵfileʵһֻڹ췽ʵ + private String name; // blob对象的名字 + FileInputStream input; // 输入流变量 + public Blob(String filename) throws Exception { // blob对象的构造方法,原有文件内容不变,生成一个文件名为hash(origin's value)的blob对象 + Hash s = new Hash(filename,true); // step1.传入一个已有的具体文件,先生成对应的hash值 + this.name = s.getSha(); // step2.为当前blob对象赋予hash值做名字 + this.input = new FileInputStream(filename); // step3.输入流变量引用由当前传入的具体文件生成的file对象实例,这一步只能在构造方法函数内实现 } - public void createBlob() throws IOException { // д봫ļݣдblobֱ档 - FileOutputStream output = new FileOutputStream(this.name); // ļڻԶ - byte[] buffer = new byte[1024]; // ַдٶȡ + public void createBlob() throws IOException { // 写入传入文件的内容,写入后用blob对象的名字保存。 + FileOutputStream output = new FileOutputStream(this.name); // 文件不存在会自动创建 + byte[] buffer = new byte[1024]; // 利用字符数组做缓冲器,提升读写速度。 int numRead = 0; do { numRead = input.read(buffer); @@ -32,13 +32,14 @@ public class Blob { output.close(); } - public String getkey() { // д봫ļݣдblobֱ档 + public String getkey() { // 写入传入文件的内容,写入后用blob对象的名字保存。 String key = this.name; return key; } + @Override - public String toString() { // дobjecttostring + public String toString() { // 重写object的tostring方法。 return "blob " + name; } } From c4a4be1b7ff86a2ce32f4c09ffff9a7c479c0ca7 Mon Sep 17 00:00:00 2001 From: bigbeats <70423253+bigbeats@users.noreply.github.com> Date: Wed, 9 Dec 2020 06:43:35 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=97=A0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重新提交一次commits --- gitcontroltool/Hash.java | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/gitcontroltool/Hash.java b/gitcontroltool/Hash.java index e5cd5ee..c397c2a 100644 --- a/gitcontroltool/Hash.java +++ b/gitcontroltool/Hash.java @@ -1,53 +1,54 @@ package gitcontroltool; import java.io.*; -import java.security.MessageDigest; // ϢժҪṩϢժҪSHA1㷨 +import java.security.MessageDigest; // 导入消息摘要,提供信息摘要SHA1算法 + public class Hash { -// shaֵļװΪһ࣬гԱsha1ʼshaֵoutFileתΪ16Ƶַ -// ṩļݣblobļַtreeshaֵͶȡṩַתַķ +// 将sha值的计算封装为一个类,该类中有成员属性sha1(初始sha值)和outFile(最终转为16进制的字符串) +// 提供基于文件内容(blob)和文件名或字符串(针对tree)的sha值计算和读取方法、提供字符数组转字符串的方法 private byte[] sha1; - public Hash(String inFile,boolean isFile) throws Exception{ // ĶʱǷļʼӦĶ˽гԱ + public Hash(String inFile,boolean isFile) throws Exception{ // 构造该类的对象时,会根据是否是文件来初始化相应的对象私有成员属性 if(isFile){ FileInputStream input = new FileInputStream(inFile); - this.sha1 = SHA1content(input); // ļݼhashֵ + this.sha1 = SHA1content(input); // 利用文件内容计算hash值 } else{ - this.sha1 = SHA1name(inFile); // ļhashֵ + this.sha1 = SHA1name(inFile); // 用文件名计算hash值 } } - public static byte[] SHA1content(InputStream is) throws Exception { // @1.һļͨļݼshaֵķblobkeyֵ - byte[] buffer = new byte[1024]; // һֽ - MessageDigest complete = MessageDigest.getInstance("SHA-1"); // ָSHA1㷨 + public static byte[] SHA1content(InputStream is) throws Exception { // @1.对一个具体文件,通过文件内容计算sha值的方法,即blob对象的key值 + byte[] buffer = new byte[1024]; // 采用一个字节数组做缓冲器 + MessageDigest complete = MessageDigest.getInstance("SHA-1"); // 指定SHA1算法 int numRead = 0; do { - numRead = is.read(buffer); // жbuffer.lengthֽڸbufferҷʵʶȡֽͱnumRead + numRead = is.read(buffer); // 从输入流中读buffer.length个字节给buffer,并且返回实际读取的字节数给整型变量numRead if (numRead > 0) { complete.update(buffer, 0, numRead); } - } while (numRead != -1); // numRead = -1ļȡϡҪرҷϢժҪֽ顣 + } while (numRead != -1); // numRead = -1代表文件读取完毕。需要关闭输入流,并且返回消息摘要字节数组。 is.close(); return complete.digest(); } - public static byte[] SHA1name(String s) throws Exception{ // @2.һļļshaֵķ + public static byte[] SHA1name(String s) throws Exception{ // @2.对一个文件或文件夹名计算sha值的方法 MessageDigest complete = MessageDigest.getInstance("SHA-1"); int numRead = 0; complete.update(s.getBytes()); return complete.digest(); } - public String convertToHexString(byte data[]) { // @3.MessageDigestdigest()صַ飬ҪõʮƵshaֵҪתΪַ - //treevalueļַļַļеtreekeyַļblobkeyַ - StringBuffer strBuffer = new StringBuffer(); // StringBufferȥɱַ + public String convertToHexString(byte data[]) { // @3.由于MessageDigest对象的digest()方法返回的是字符数组,要得到十六进制的sha值还需要转为字符串 + //(tree的value包括了文件名(字符串)、子文件夹名(字符串)、子文件夹的treekey(字符串)、子文件的blobkey(字符串) + StringBuffer strBuffer = new StringBuffer(); // 用StringBuffer去建立可变字符串对象 for (int i = 0; i < data.length; i++) { - strBuffer.append(Integer.toHexString(0xff & data[i])); // ʮoxffijֵֽλ㣬 - // ֻ32λ8λ֤תʮƲ + strBuffer.append(Integer.toHexString(0xff & data[i])); // 用十六进制数oxff与某个字节值做按位与运算, + // 只保留了32位的最后8位,保证负数转换成十六进制不会出错 } return strBuffer.toString(); } public String getSha() { // return convertToHexString(sha1); } -} \ No newline at end of file +} From 409e9f2e78d0b406690db7065eb085cf5e97ce72 Mon Sep 17 00:00:00 2001 From: bigbeats <70423253+bigbeats@users.noreply.github.com> Date: Wed, 9 Dec 2020 06:43:52 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=97=A0=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 重新提交一次commits --- gitcontroltool/Test.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/gitcontroltool/Test.java b/gitcontroltool/Test.java index f156c62..ecb4ee5 100644 --- a/gitcontroltool/Test.java +++ b/gitcontroltool/Test.java @@ -1,12 +1,13 @@ package gitcontroltool; import java.io.*; -// ԪЧ -// һļݣ洢ӶӦkey-valuekeyҵõӦvalueֵ +// 单元测试类测试最终效果 +// 即给定一个文件内容,向存储中添加对应的key-value;给定key,查找得到对应的value值 + public class Test { - public static void testValid(String filename){ // testvalidǷһhashvaluekeyֵΪļļ -// һoriginļƣһhashorigins valueֵļļͬorigin + public static void testValid(String filename){ // testvalid函数测试是否可以生成一个以hash(value)即key值为文件名的新文件 +// 传入一个具体的origin文件名称,生成一个hash(origin‘s value)做名字的新文件,文件内容同origin。 File file = new File(filename); try{ Blob blob = new Blob(file.getAbsolutePath()); @@ -14,12 +15,12 @@ public class Test { System.out.println(blob); } catch (Exception ex){ - ex.printStackTrace(); // дӡ쳣Ϣڳгλüԭ + ex.printStackTrace(); // 在命令行打印异常信息在程序中出错的位置及原因 } } public static void getValue(String path, String encoding) throws IOException { - // testValid()ɵkeyֵΪļļgetValueȥõӦvalue + // 根据testValid()方法生成的key值为文件名的文件,现在用getValue方法去得到对应的value String content = ""; File file = new File(path); BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), encoding)); @@ -37,4 +38,4 @@ public static void main(String[] args) throws IOException { String testfile = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed"; getValue(testfile,"utf-8"); } -} \ No newline at end of file +} From 2e4f8f19cc50814f29f5dfa8a61d967e3f152e35 Mon Sep 17 00:00:00 2001 From: withjiang <70436180+withjiang@users.noreply.github.com> Date: Tue, 15 Dec 2020 23:42:08 +0800 Subject: [PATCH 4/4] =?UTF-8?q?Create=20=E4=BB=BB=E5=8A=A1=E4=B8=80?= =?UTF-8?q?=E8=AF=A6=E7=BB=86=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...7\246\347\273\206\346\226\207\346\241\243" | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 "gitcontroltool/\344\273\273\345\212\241\344\270\200\350\257\246\347\273\206\346\226\207\346\241\243" diff --git "a/gitcontroltool/\344\273\273\345\212\241\344\270\200\350\257\246\347\273\206\346\226\207\346\241\243" "b/gitcontroltool/\344\273\273\345\212\241\344\270\200\350\257\246\347\273\206\346\226\207\346\241\243" new file mode 100644 index 0000000..8a66225 --- /dev/null +++ "b/gitcontroltool/\344\273\273\345\212\241\344\270\200\350\257\246\347\273\206\346\226\207\346\241\243" @@ -0,0 +1,49 @@ +课程项目: +参考git实现原理,使用Java实现blob、tree、commit核心存储结构 +功能: +1.Commit:提交commit,可以使用”git log”查看commit历史 +2.回滚 使用”git reset” 回滚到指定分支 +3.分支 创建分支、实现分支间切换 + +第一周任务: +(1)文件的key-value: +实现key-value存储(封装为class): +Key:文件名 +Value:文件中内容(key根据value计算得出) +功能: +1.给定value,向存储中添加对应的key-value +2.给定key,查找得到对应的value + +(2)文件夹的key-value存储: + 遍历文件夹目录, 如果遇到子文件则转化为blob并保存 + 如果遇到子文件夹则递归调用内部的文件夹或文件,转化为blob与tree +并保存 + +(3)单元测试(unittest) + 通过代码自动化的检测key-value存储实现是否正确,确保大量文件进行存储时的效率与正确率。 + + +存储目标分析: +(1)blob文件的value:文件内容 + Key:value的hash值 +(2)tree文件夹的value:内部blob文件的key、每个子文件夹tree的key、子文件以及子 +文件夹的名称 + Key:tree文件夹value的hash值 + +实现设计: +(1)hash类:计算文件blob、文件夹tree的hash值。 +-计算字符串(string型)参数的hash方法 +-计算file的hash方法 +-返回得到的hash值 +(2)<优化后>KeyValueObject: blob、tree的父类,子类blob与tree继承自object类 + 计算key值 + 创建类型为blob类型的文件 + 创建类型为tree类型的文件 + +(3)blob类: +计算该blob文件的key +创建以key命名的blob文件 + +(4)tree类: +计算该tree文件的key值 +以key命名的tree文件