nv-hash-file 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -0
- package/index.js +171 -0
- package/package.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
|
|
2
|
+
nv-hash-file
|
|
3
|
+
=======================
|
|
4
|
+
- fast and high conflict file content hash
|
|
5
|
+
- for estimate using, normally useless
|
|
6
|
+
|
|
7
|
+
install
|
|
8
|
+
=======
|
|
9
|
+
- npm install nv-hash-file
|
|
10
|
+
|
|
11
|
+
usage
|
|
12
|
+
=====
|
|
13
|
+
|
|
14
|
+
const { } = require("nv-hash-file");
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
example
|
|
18
|
+
-------
|
|
19
|
+
|
|
20
|
+
### 0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
#### 0_0
|
|
24
|
+
|
|
25
|
+
#### 0_1
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
### 1
|
|
29
|
+
|
|
30
|
+
#### 1_0
|
|
31
|
+
|
|
32
|
+
#### 1_1
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
METHODS
|
|
36
|
+
========
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
APIS
|
|
40
|
+
=======
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
LICENSE
|
|
44
|
+
=======
|
|
45
|
+
- ISC
|
|
46
|
+
|
package/index.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const _fs = require("fs");
|
|
2
|
+
const _path = require("path");
|
|
3
|
+
|
|
4
|
+
const _cmp_file_byte_by_byte = (p0, p1) => {
|
|
5
|
+
const fd0 = _fs.openSync(p0, 'r');
|
|
6
|
+
const fd1 = _fs.openSync(p1, 'r');
|
|
7
|
+
const buf0 = Buffer.alloc(4096);
|
|
8
|
+
const buf1 = Buffer.alloc(4096);
|
|
9
|
+
|
|
10
|
+
let offset = 0;
|
|
11
|
+
while (true) {
|
|
12
|
+
const bytesRead0 = _fs.readSync(fd0, buf0, 0, buf0.length, offset);
|
|
13
|
+
const bytesRead1 = _fs.readSync(fd1, buf1, 0, buf1.length, offset);
|
|
14
|
+
|
|
15
|
+
const minLen = Math.min(bytesRead0, bytesRead1);
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < minLen; i++) {
|
|
18
|
+
if (buf0[i] < buf1[i]) {
|
|
19
|
+
_fs.closeSync(fd0);
|
|
20
|
+
_fs.closeSync(fd1);
|
|
21
|
+
return -1;
|
|
22
|
+
}
|
|
23
|
+
if (buf0[i] > buf1[i]) {
|
|
24
|
+
_fs.closeSync(fd0);
|
|
25
|
+
_fs.closeSync(fd1);
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// 如果读取的字节数不同,较长的文件更大
|
|
31
|
+
if (bytesRead0 < bytesRead1) {
|
|
32
|
+
_fs.closeSync(fd0);
|
|
33
|
+
_fs.closeSync(fd1);
|
|
34
|
+
return -1;
|
|
35
|
+
}
|
|
36
|
+
if (bytesRead0 > bytesRead1) {
|
|
37
|
+
_fs.closeSync(fd0);
|
|
38
|
+
_fs.closeSync(fd1);
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 两者都读完且没有差异
|
|
43
|
+
if (bytesRead0 === 0) {
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
offset += minLen;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
_fs.closeSync(fd0);
|
|
51
|
+
_fs.closeSync(fd1);
|
|
52
|
+
return 0;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const _eq_byte_by_byte = (p0, p1) => _cmp_file_byte_by_byte(p0,p1)===0;
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
const cmp_file_byte_by_byte = (p0,p1)=>{
|
|
59
|
+
p0 = _path.resolve(p0);
|
|
60
|
+
p1 = _path.resolve(p1);
|
|
61
|
+
if(_fs.existsSync(p0)) {
|
|
62
|
+
if(_fs.existsSync(p1)) {
|
|
63
|
+
var stat0 = _fs.lstatSync(p0);
|
|
64
|
+
if(stat0.isFile()) {
|
|
65
|
+
var stat1 = _fs.lstatSync(p1);
|
|
66
|
+
if(stat1.isFile()) {
|
|
67
|
+
return [true,_cmp_file_byte_by_byte(p0,p1)];
|
|
68
|
+
} else {
|
|
69
|
+
return [false, `${p1} NOT file`];
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
return [false, `${p0} NOT file`];
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
return [false, `${p1} NOT exist`];
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
return [false, `${p0} NOT exist`];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const eq_byte_by_byte = (p0, p1) => {
|
|
82
|
+
var pair = cmp_file_byte_by_byte(p0,p1);
|
|
83
|
+
if(pair[0]) {
|
|
84
|
+
return pair[1] === 0;
|
|
85
|
+
} else {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
const _hash = (p) => {
|
|
92
|
+
const stat = _fs.lstatSync(p);
|
|
93
|
+
if (!stat.isFile()) { return -1;}
|
|
94
|
+
const sz = stat.size;
|
|
95
|
+
if(sz === 0) {return 0;}
|
|
96
|
+
// 打开文件读二进制
|
|
97
|
+
const fd = _fs.openSync(p, 'r');
|
|
98
|
+
const buf = Buffer.alloc(1);
|
|
99
|
+
// 读取第一个字节
|
|
100
|
+
_fs.readSync(fd, buf, 0, 1, 0);
|
|
101
|
+
const fst = buf[0];
|
|
102
|
+
// 读取中间字节
|
|
103
|
+
let mid;
|
|
104
|
+
if (sz % 2 === 1) {
|
|
105
|
+
// 奇数长度:取正中间那一个字节
|
|
106
|
+
const midPos = Math.floor(sz / 2); // 例如 sz=5 → midPos=2
|
|
107
|
+
_fs.readSync(fd, buf, 0, 1, midPos);
|
|
108
|
+
mid = buf[0];
|
|
109
|
+
} else {
|
|
110
|
+
// 偶数长度:取中间两个字节,求和后右移 1 位
|
|
111
|
+
const leftPos = sz / 2 - 1; // 例如 sz=6 → leftPos=2
|
|
112
|
+
const rightPos = sz / 2; // rightPos=3
|
|
113
|
+
_fs.readSync(fd, buf, 0, 1, leftPos);
|
|
114
|
+
const leftByte = buf[0];
|
|
115
|
+
_fs.readSync(fd, buf, 0, 1, rightPos);
|
|
116
|
+
const rightByte = buf[0];
|
|
117
|
+
mid = (leftByte + rightByte) >> 1; // 求和后除以 2(取整)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 读取最后一个字节
|
|
121
|
+
_fs.readSync(fd, buf, 0, 1, sz - 1);
|
|
122
|
+
const lst = buf[0];
|
|
123
|
+
|
|
124
|
+
_fs.closeSync(fd);
|
|
125
|
+
|
|
126
|
+
// 组合哈希
|
|
127
|
+
const h0 = sz % (2 ** 28); // 高 28 位:size 低 28 位
|
|
128
|
+
const h1 = (fst << 16) | (mid << 8) | lst; // 低 24 位:3 个字节
|
|
129
|
+
const h = (h0 * (2 ** 24)) + h1; // 最终哈希
|
|
130
|
+
return h;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const hash = (p) => {
|
|
134
|
+
p = _path.resolve(p);
|
|
135
|
+
if (_fs.existsSync(p)) {
|
|
136
|
+
return _hash(p);
|
|
137
|
+
} else {
|
|
138
|
+
return -2;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const _eq = (p0,p1)=>{
|
|
143
|
+
var h0 = _hash(p0);
|
|
144
|
+
var h1 = _hash(p1);
|
|
145
|
+
if(h0===h1 && h0 >=0) {
|
|
146
|
+
return _eq_byte_by_byte(p0,p1);
|
|
147
|
+
} else {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const eq = (p0,p1)=>{
|
|
153
|
+
var h0 = hash(p0);
|
|
154
|
+
var h1 = hash(p1);
|
|
155
|
+
if(h0===h1) {
|
|
156
|
+
return _eq_byte_by_byte(p0,p1);
|
|
157
|
+
} else {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
module.exports = hash;
|
|
164
|
+
module.exports._hash = hash;
|
|
165
|
+
module.exports._cmp_file_byte_by_byte = _cmp_file_byte_by_byte;
|
|
166
|
+
module.exports.cmp_file_byte_by_byte = cmp_file_byte_by_byte;
|
|
167
|
+
module.exports._eq_byte_by_byte = _eq_byte_by_byte;
|
|
168
|
+
module.exports.eq_byte_by_byte = eq_byte_by_byte;
|
|
169
|
+
module.exports._eq = _eq;
|
|
170
|
+
module.exports.eq = eq;
|
|
171
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nv-hash-file",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"main": "index.js",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
},
|
|
8
|
+
"author": "",
|
|
9
|
+
"license": "ISC",
|
|
10
|
+
"description": "",
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"nv-array-eqgrp": "^1.0.0",
|
|
13
|
+
"nv-array-group-by": "^1.0.2"
|
|
14
|
+
}
|
|
15
|
+
}
|