vvvfs 0.1.1 → 0.1.2

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 CHANGED
@@ -50,6 +50,7 @@ const vvvfs = new VVVFS("vvvfs", {
50
50
  await vvvfs.writeText("/home/user/Desktop/test.txt", "Hello World!"); // 写入文本文件,写入文件还包括write(path: string, content: Blob)和writeJson(path: string, content: Record<string, any>)方法,返回true和false
51
51
  await vvvfs.appendText("/home/user/Desktop/test.txt", "Hello World!"); // 追加文本文件,返回true和false
52
52
  console.log(await vvvfs.readText("/home/user/Desktop/test.txt")); // 读取文本文件,读取文件还包括read(path: string): Blob | null和readJson(path: string): Record<string, any> | null方法
53
+ console.log(await vvvfs.readChunkText("/home/user/Desktop/test.txt", 0, 5)); // 读取文件块,返回string | null
53
54
  await vvvfs.delete("/home/user/Desktop/test.txt"); // 删除文件,返回true和false
54
55
  if (await vvvfs.exists("/home/user/Desktop")) {
55
56
  // 判断文件或目录是否存在
@@ -83,6 +84,10 @@ const vvvfs = new VVVFS("vvvfs", {
83
84
 
84
85
  ## 更新日志
85
86
 
87
+ ### 0.1.2
88
+
89
+ - 新增 `readChunk` 和 `readChunkText` 方法,用于读取文件块
90
+
86
91
  ### 0.1.1
87
92
 
88
93
  - 新增 `append` 和 `appendText` 方法,用于追加内容
package/index.html CHANGED
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html lang="en">
2
+ <html lang="zh-CN">
3
3
 
4
4
  <head>
5
5
  <meta charset="UTF-8">
@@ -27,6 +27,7 @@
27
27
  console.log("文件是否存在", await vvvfs.exists("/test.txt"));
28
28
  console.log("文件是否存在", await vvvfs.exists("/test2.txt"));
29
29
  console.log("读取文件", await vvvfs.readText("/test.txt"));
30
+ console.log("读取文件块", await vvvfs.readTextChunk("/test.txt", 0, 5));
30
31
  console.log("复制文件", await vvvfs.copy("/test.txt", "/test2.txt"));
31
32
  console.log("搜索文件", await vvvfs.search("/", "t"));
32
33
  console.log("移动文件", await vvvfs.move("/test2.txt", "/test3.txt"));
package/index.ts CHANGED
@@ -129,6 +129,22 @@ class VVVFSFile {
129
129
  async readJSON() {
130
130
  return await this._vvvfs.readJson(this._path);
131
131
  }
132
+ /**
133
+ * 读取文件内容
134
+ * @param start 起始位置
135
+ * @param end 结束位置
136
+ */
137
+ async readChunk(start: number, end: number) {
138
+ return await this._vvvfs.readChunk(this._path, start, end);
139
+ }
140
+ /**
141
+ * 读取文件内容
142
+ * @param start 起始位置
143
+ * @param end 结束位置
144
+ */
145
+ async readTextChunk(start: number, end: number) {
146
+ return await this._vvvfs.readTextChunk(this._path, start, end);
147
+ }
132
148
  /**
133
149
  * 写入文件
134
150
  * @param file 文件对象
@@ -238,7 +254,7 @@ class VVVFSFile {
238
254
  const version = packageJson.version;
239
255
  class VVVFS {
240
256
  static defaultDBName = "vvvfs";
241
- private db: VVVFSDatabase;
257
+ #db: VVVFSDatabase;
242
258
  options: VVVFSOptions;
243
259
  /**
244
260
  * 虚拟文件系统版本
@@ -251,7 +267,7 @@ class VVVFS {
251
267
  /**
252
268
  * 虚拟文件系统监听器
253
269
  */
254
- watchers: Record<string, Array<(type: string) => Promise<boolean>>> = {};
270
+ #watchers: Record<string, Array<(type: string) => Promise<boolean>>> = {};
255
271
  /**
256
272
  * 创建虚拟文件系统
257
273
  * @param name 虚拟文件系统名称
@@ -265,8 +281,8 @@ class VVVFS {
265
281
  ) {
266
282
  this.options = options;
267
283
  try {
268
- this.db = new Dexie(name || VVVFS.defaultDBName) as VVVFSDatabase;
269
- this.db.version(1).stores({
284
+ this.#db = new Dexie(name || VVVFS.defaultDBName) as VVVFSDatabase;
285
+ this.#db.version(1).stores({
270
286
  files: "++id, name, path, type, file, [name+path+type]",
271
287
  });
272
288
  } catch (error) {
@@ -404,7 +420,7 @@ class VVVFS {
404
420
  try {
405
421
  for (const file of linuxInitFiles) {
406
422
  if (await this.exists(file.path)) continue;
407
- await this.db.files.put(file);
423
+ await this.#db.files.put(file);
408
424
  }
409
425
  } catch (error) {
410
426
  console.error("初始化文件失败", error);
@@ -416,9 +432,9 @@ class VVVFS {
416
432
  */
417
433
  async reset() {
418
434
  try {
419
- await this.db.delete();
420
- this.db = new Dexie(this.db.name) as VVVFSDatabase;
421
- this.db.version(1).stores({
435
+ await this.#db.delete();
436
+ this.#db = new Dexie(this.#db.name) as VVVFSDatabase;
437
+ this.#db.version(1).stores({
422
438
  files: "++id, name, path, type, file, [name+path+type]",
423
439
  });
424
440
  } catch (error) {
@@ -433,8 +449,8 @@ class VVVFS {
433
449
  async createFile(path: string) {
434
450
  const targetPath = joinPath(path);
435
451
  try {
436
- if (this.watchers[targetPath]) {
437
- for (const handler of this.watchers[targetPath]) {
452
+ if (this.#watchers[targetPath]) {
453
+ for (const handler of this.#watchers[targetPath]) {
438
454
  if (await handler("create")) {
439
455
  if (this.options.throwError) {
440
456
  throw new VVVFSError("CreateFile", "创建文件失败:监听器取消了操作");
@@ -451,7 +467,7 @@ class VVVFS {
451
467
  if (!(await this.exists(parent))) {
452
468
  await this.createDir(parent);
453
469
  }
454
- await this.db.files.add({
470
+ await this.#db.files.add({
455
471
  name: name,
456
472
  path: parent,
457
473
  type: "file",
@@ -475,8 +491,8 @@ class VVVFS {
475
491
  async createDir(path: string) {
476
492
  const targetPath = joinPath(path);
477
493
  try {
478
- if (this.watchers[targetPath]) {
479
- for (const handler of this.watchers[targetPath]) {
494
+ if (this.#watchers[targetPath]) {
495
+ for (const handler of this.#watchers[targetPath]) {
480
496
  if (await handler("create")) {
481
497
  if (this.options.throwError) {
482
498
  throw new VVVFSError("CreateDir", "创建目录失败:监听器取消了操作");
@@ -492,7 +508,7 @@ class VVVFS {
492
508
  const { name, parent } = parsePath(targetPath);
493
509
  if (!(await this.exists(parent))) {
494
510
  if (parent == "/") {
495
- await this.db.files.add({
511
+ await this.#db.files.add({
496
512
  name: "",
497
513
  path: "/",
498
514
  type: "dir",
@@ -503,7 +519,7 @@ class VVVFS {
503
519
  await this.createDir(parent);
504
520
  }
505
521
  }
506
- await this.db.files.add({
522
+ await this.#db.files.add({
507
523
  name: name,
508
524
  path: parent,
509
525
  type: "dir",
@@ -527,7 +543,7 @@ class VVVFS {
527
543
  const targetPath = joinPath(path);
528
544
  const { name, parent } = parsePath(targetPath);
529
545
  return (
530
- (await this.db.files
546
+ (await this.#db.files
531
547
  .where({
532
548
  name: name,
533
549
  path: parent,
@@ -549,8 +565,8 @@ class VVVFS {
549
565
  async write(path: string, content: Blob) {
550
566
  try {
551
567
  const targetPath = joinPath(path);
552
- if (this.watchers[targetPath]) {
553
- for (const handler of this.watchers[targetPath]) {
568
+ if (this.#watchers[targetPath]) {
569
+ for (const handler of this.#watchers[targetPath]) {
554
570
  if (await handler("write")) {
555
571
  if (this.options.throwError) {
556
572
  throw new VVVFSError("Write", "写入文件失败:监听器取消了操作");
@@ -580,9 +596,9 @@ class VVVFS {
580
596
  const file = new File([content], name, {
581
597
  type: mime.getType(targetPath) || "application/octet-stream",
582
598
  });
583
- const fileRecord = await this.db.files.where({ name, path: parent }).first();
599
+ const fileRecord = await this.#db.files.where({ name, path: parent }).first();
584
600
  if (fileRecord) {
585
- await this.db.files.put({
601
+ await this.#db.files.put({
586
602
  ...fileRecord,
587
603
  file: file,
588
604
  });
@@ -647,8 +663,8 @@ class VVVFS {
647
663
  async append(path: string, content: Blob) {
648
664
  try {
649
665
  const targetPath = joinPath(path);
650
- if (this.watchers[targetPath]) {
651
- for (const handler of this.watchers[targetPath]) {
666
+ if (this.#watchers[targetPath]) {
667
+ for (const handler of this.#watchers[targetPath]) {
652
668
  if (await handler("append")) {
653
669
  if (this.options.throwError) {
654
670
  throw new VVVFSError("Append", "追加文件失败:监听器取消了操作");
@@ -698,8 +714,8 @@ class VVVFS {
698
714
  async read(path: string) {
699
715
  try {
700
716
  const targetPath = joinPath(path);
701
- if (this.watchers[targetPath]) {
702
- for (const handler of this.watchers[targetPath]) {
717
+ if (this.#watchers[targetPath]) {
718
+ for (const handler of this.#watchers[targetPath]) {
703
719
  if (await handler("read")) {
704
720
  if (this.options.throwError) {
705
721
  throw new VVVFSError("Read", "读取文件失败:监听器取消了操作");
@@ -716,7 +732,7 @@ class VVVFS {
716
732
  return null;
717
733
  }
718
734
  const { name, parent } = parsePath(targetPath);
719
- return (await this.db.files.where({ name, path: parent }).first())?.file;
735
+ return (await this.#db.files.where({ name, path: parent }).first())?.file;
720
736
  } catch (error) {
721
737
  console.error("读取文件失败", error);
722
738
  if (this.options.throwError) {
@@ -777,6 +793,63 @@ class VVVFS {
777
793
  return null;
778
794
  }
779
795
  }
796
+ /**
797
+ * 读取文件内容
798
+ * @param path 文件路径
799
+ * @param start 开始位置
800
+ * @param end 结束位置
801
+ */
802
+ async readChunk(path: string, start: number, end: number) {
803
+ try {
804
+ const targetPath = joinPath(path);
805
+ if (this.#watchers[targetPath]) {
806
+ for (const handler of this.#watchers[targetPath]) {
807
+ if (await handler("read")) {
808
+ if (this.options.throwError) {
809
+ throw new VVVFSError("Read", "读取文件失败:监听器取消了操作");
810
+ }
811
+ return null;
812
+ }
813
+ }
814
+ }
815
+ if (!(await this.exists(targetPath))) {
816
+ console.warn("文件不存在");
817
+ if (this.options.throwError) {
818
+ throw new VVVFSError("Read", "文件不存在");
819
+ }
820
+ return null;
821
+ }
822
+ const file = await this.read(targetPath);
823
+ return file?.slice(start, end) || null;
824
+ } catch (error) {
825
+ console.error("读取文件失败", error);
826
+ if (this.options.throwError) {
827
+ throw new VVVFSError("Read", "读取文件失败" + error);
828
+ }
829
+ return null;
830
+ }
831
+ }
832
+ /**
833
+ * 读取文件内容
834
+ * @param path 文件路径
835
+ * @param start 读取开始位置
836
+ * @param end 读取结束位置
837
+ */
838
+ async readTextChunk(path: string, start: number, end: number) {
839
+ try {
840
+ const chunk = await this.readChunk(path, start, end);
841
+ if (chunk) {
842
+ return await chunk.text();
843
+ } else {
844
+ return null;
845
+ }
846
+ } catch (error) {
847
+ console.error("读取文件失败", error);
848
+ if (this.options.throwError) {
849
+ throw new VVVFSError("Read", "读取文件失败" + error);
850
+ }
851
+ }
852
+ }
780
853
  /**
781
854
  * 判断是否是文件
782
855
  * @param path 文件路径
@@ -785,7 +858,7 @@ class VVVFS {
785
858
  try {
786
859
  const targetPath = joinPath(path);
787
860
  const { name, parent } = parsePath(targetPath);
788
- return (await this.db.files.where({ name, path: parent, type: "file" }).count()) > 0;
861
+ return (await this.#db.files.where({ name, path: parent, type: "file" }).count()) > 0;
789
862
  } catch (error) {
790
863
  console.error("判断文件类型失败", error);
791
864
  if (this.options.throwError) {
@@ -802,7 +875,7 @@ class VVVFS {
802
875
  try {
803
876
  const targetPath = joinPath(path);
804
877
  const { name, parent } = parsePath(targetPath);
805
- return (await this.db.files.where({ path: parent, name, type: "dir" }).count()) > 0;
878
+ return (await this.#db.files.where({ path: parent, name, type: "dir" }).count()) > 0;
806
879
  } catch (error) {
807
880
  console.error("判断文件类型失败", error);
808
881
  if (this.options.throwError) {
@@ -818,8 +891,8 @@ class VVVFS {
818
891
  async list(path: string) {
819
892
  try {
820
893
  const targetPath = joinPath(path);
821
- if (this.watchers[targetPath]) {
822
- for (const handler of this.watchers[targetPath]) {
894
+ if (this.#watchers[targetPath]) {
895
+ for (const handler of this.#watchers[targetPath]) {
823
896
  if (await handler("list")) {
824
897
  if (this.options.throwError) {
825
898
  throw new VVVFSError("List", "列出目录下的文件失败:监听器取消了操作");
@@ -842,7 +915,7 @@ class VVVFS {
842
915
  }
843
916
  return [];
844
917
  }
845
- return (await this.db.files.where({ path: targetPath }).toArray())
918
+ return (await this.#db.files.where({ path: targetPath }).toArray())
846
919
  .map((file) => file.name)
847
920
  .filter((item) => item != "");
848
921
  } catch (error) {
@@ -862,8 +935,8 @@ class VVVFS {
862
935
  try {
863
936
  const sourcePath = joinPath(path);
864
937
  const { name, parent } = parsePath(sourcePath);
865
- if (this.watchers[sourcePath]) {
866
- for (const handler of this.watchers[sourcePath]) {
938
+ if (this.#watchers[sourcePath]) {
939
+ for (const handler of this.#watchers[sourcePath]) {
867
940
  if (await handler("rename")) {
868
941
  if (this.options.throwError) {
869
942
  throw new VVVFSError("Rename", "重命名文件失败:监听器取消了操作");
@@ -890,7 +963,7 @@ class VVVFS {
890
963
  }
891
964
  return false;
892
965
  }
893
- const fileRecord = await this.db.files.where({ path: parent, name }).first();
966
+ const fileRecord = await this.#db.files.where({ path: parent, name }).first();
894
967
  if (!fileRecord) {
895
968
  console.warn("文件记录未找到");
896
969
  if (this.options.throwError) {
@@ -899,7 +972,7 @@ class VVVFS {
899
972
  return false;
900
973
  }
901
974
  if (fileRecord.type === "dir") {
902
- const descendants = await this.db.files
975
+ const descendants = await this.#db.files
903
976
  .filter(
904
977
  (file) =>
905
978
  file.path === sourcePath || file.path.startsWith(sourcePath + "/"),
@@ -908,10 +981,10 @@ class VVVFS {
908
981
  for (const descendant of descendants) {
909
982
  const relativePath = descendant.path.slice(sourcePath.length);
910
983
  const updatedPath = joinPath(newPath + relativePath);
911
- await this.db.files.update(descendant.id!, { path: updatedPath });
984
+ await this.#db.files.update(descendant.id!, { path: updatedPath });
912
985
  }
913
986
  }
914
- await this.db.files.update(fileRecord.id!, {
987
+ await this.#db.files.update(fileRecord.id!, {
915
988
  name: newName,
916
989
  path: parent,
917
990
  });
@@ -931,8 +1004,8 @@ class VVVFS {
931
1004
  async delete(path: string) {
932
1005
  try {
933
1006
  const targetPath = joinPath(path);
934
- if (this.watchers[targetPath]) {
935
- for (const handler of this.watchers[targetPath]) {
1007
+ if (this.#watchers[targetPath]) {
1008
+ for (const handler of this.#watchers[targetPath]) {
936
1009
  if (await handler("delete")) {
937
1010
  if (this.options.throwError) {
938
1011
  throw new VVVFSError("Delete", "删除文件失败:监听器取消了操作");
@@ -954,19 +1027,19 @@ class VVVFS {
954
1027
  for (const file of files) {
955
1028
  await this.delete(joinPath(targetPath, file));
956
1029
  }
957
- const dirRecord = await this.db.files
1030
+ const dirRecord = await this.#db.files
958
1031
  .where({ name, path: parent, type: "dir" })
959
1032
  .first();
960
1033
  if (dirRecord) {
961
- await this.db.files.delete(dirRecord.id!);
1034
+ await this.#db.files.delete(dirRecord.id!);
962
1035
  }
963
1036
  return true;
964
1037
  } else {
965
- const fileRecord = await this.db.files
1038
+ const fileRecord = await this.#db.files
966
1039
  .where({ name, path: parent, type: "file" })
967
1040
  .first();
968
1041
  if (fileRecord) {
969
- await this.db.files.delete(fileRecord.id!);
1042
+ await this.#db.files.delete(fileRecord.id!);
970
1043
  }
971
1044
  return true;
972
1045
  }
@@ -987,8 +1060,8 @@ class VVVFS {
987
1060
  try {
988
1061
  const sourcePath = joinPath(path);
989
1062
  const destinationPath = joinPath(newPath);
990
- if (this.watchers[sourcePath]) {
991
- for (const handler of this.watchers[sourcePath]) {
1063
+ if (this.#watchers[sourcePath]) {
1064
+ for (const handler of this.#watchers[sourcePath]) {
992
1065
  if (await handler("move")) {
993
1066
  if (this.options.throwError) {
994
1067
  throw new VVVFSError("Move", "移动文件失败:监听器取消了操作");
@@ -1029,20 +1102,20 @@ class VVVFS {
1029
1102
  for (const child of children) {
1030
1103
  await this.move(joinPath(sourcePath, child), joinPath(destinationPath, child));
1031
1104
  }
1032
- const dirRecord = await this.db.files
1105
+ const dirRecord = await this.#db.files
1033
1106
  .where({ name, path: parent, type: "dir" })
1034
1107
  .first();
1035
1108
  if (dirRecord) {
1036
- await this.db.files.delete(dirRecord.id!);
1109
+ await this.#db.files.delete(dirRecord.id!);
1037
1110
  }
1038
1111
  return true;
1039
1112
  } else {
1040
1113
  await this.createDir(newParent);
1041
- const fileRecord = await this.db.files
1114
+ const fileRecord = await this.#db.files
1042
1115
  .where({ name, path: parent, type: "file" })
1043
1116
  .first();
1044
1117
  if (fileRecord) {
1045
- await this.db.files.update(fileRecord.id!, { name: newName, path: newParent });
1118
+ await this.#db.files.update(fileRecord.id!, { name: newName, path: newParent });
1046
1119
  return true;
1047
1120
  }
1048
1121
  return false;
@@ -1064,8 +1137,8 @@ class VVVFS {
1064
1137
  try {
1065
1138
  const sourcePath = joinPath(path);
1066
1139
  const destinationPath = joinPath(newPath);
1067
- if (this.watchers[sourcePath]) {
1068
- for (const handler of this.watchers[sourcePath]) {
1140
+ if (this.#watchers[sourcePath]) {
1141
+ for (const handler of this.#watchers[sourcePath]) {
1069
1142
  if (await handler("copy")) {
1070
1143
  if (this.options.throwError) {
1071
1144
  throw new VVVFSError("Copy", "复制文件失败:监听器取消了操作");
@@ -1105,11 +1178,11 @@ class VVVFS {
1105
1178
  }
1106
1179
  return true;
1107
1180
  } else {
1108
- const fileRecord = await this.db.files
1181
+ const fileRecord = await this.#db.files
1109
1182
  .where({ name, path: parent, type: "file" })
1110
1183
  .first();
1111
1184
  if (fileRecord) {
1112
- await this.db.files.add({
1185
+ await this.#db.files.add({
1113
1186
  name: newName,
1114
1187
  path: newParent,
1115
1188
  type: fileRecord.type,
@@ -1179,10 +1252,10 @@ class VVVFS {
1179
1252
  }
1180
1253
  async watch(path: string, handler: (type: string) => Promise<boolean>) {
1181
1254
  path = joinPath(path);
1182
- if (!this.watchers[path]) {
1183
- this.watchers[path] = [];
1255
+ if (!this.#watchers[path]) {
1256
+ this.#watchers[path] = [];
1184
1257
  }
1185
- this.watchers[path].push(handler);
1258
+ this.#watchers[path].push(handler);
1186
1259
  }
1187
1260
  }
1188
1261
  function parsePath(path: string) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vvvfs",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "一个使用IndexDB实现的虚拟文件系统",
5
5
  "keywords": [
6
6
  "Virtual",