@giszhc/file-utils 0.0.1
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 +710 -0
- package/dist/file-utils.js +349 -0
- package/package.json +36 -0
- package/types/convert.d.ts +37 -0
- package/types/download.d.ts +96 -0
- package/types/generate.d.ts +93 -0
- package/types/index.d.ts +44 -0
- package/types/read.d.ts +70 -0
- package/types/utils.d.ts +43 -0
- package/types/validators.d.ts +107 -0
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
function p(e, t = "text") {
|
|
2
|
+
return new Promise((n, r) => {
|
|
3
|
+
const o = new FileReader();
|
|
4
|
+
switch (t) {
|
|
5
|
+
case "text":
|
|
6
|
+
o.readAsText(e);
|
|
7
|
+
break;
|
|
8
|
+
case "arrayBuffer":
|
|
9
|
+
o.readAsArrayBuffer(e);
|
|
10
|
+
break;
|
|
11
|
+
case "dataURL":
|
|
12
|
+
o.readAsDataURL(e);
|
|
13
|
+
break;
|
|
14
|
+
case "binaryString":
|
|
15
|
+
o.readAsBinaryString(e);
|
|
16
|
+
break;
|
|
17
|
+
default:
|
|
18
|
+
o.readAsText(e);
|
|
19
|
+
}
|
|
20
|
+
o.onload = (i) => {
|
|
21
|
+
const a = i.target?.result;
|
|
22
|
+
a !== void 0 ? n(a) : r(new Error("文件读取失败"));
|
|
23
|
+
}, o.onerror = () => {
|
|
24
|
+
r(new Error("文件读取错误"));
|
|
25
|
+
}, o.onabort = () => {
|
|
26
|
+
r(new Error("文件读取被中止"));
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
async function S(e, t = "utf-8") {
|
|
31
|
+
return new Promise((n, r) => {
|
|
32
|
+
const o = new FileReader();
|
|
33
|
+
o.readAsText(e, t), o.onload = (i) => {
|
|
34
|
+
const a = i.target?.result;
|
|
35
|
+
a !== void 0 ? n(a) : r(new Error("文件读取失败"));
|
|
36
|
+
}, o.onerror = () => {
|
|
37
|
+
r(new Error("文件读取错误"));
|
|
38
|
+
}, o.onabort = () => {
|
|
39
|
+
r(new Error("文件读取被中止"));
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function W(e, t = {}) {
|
|
44
|
+
const { separator: n = ",", hasHeader: r = !0 } = t, o = await p(e, "text");
|
|
45
|
+
if (!o.trim())
|
|
46
|
+
return [];
|
|
47
|
+
const i = o.split(/\r?\n/).filter((h) => h.trim() !== "");
|
|
48
|
+
if (i.length === 0)
|
|
49
|
+
return [];
|
|
50
|
+
let a = [], s = 0;
|
|
51
|
+
r && (a = b(i[0], n), s = 1);
|
|
52
|
+
const d = [];
|
|
53
|
+
for (let h = s; h < i.length; h++) {
|
|
54
|
+
const l = b(i[h], n);
|
|
55
|
+
if (r && a.length > 0) {
|
|
56
|
+
const u = {};
|
|
57
|
+
a.forEach((c, f) => {
|
|
58
|
+
u[c] = l[f] || "";
|
|
59
|
+
}), d.push(u);
|
|
60
|
+
} else
|
|
61
|
+
d.push(l);
|
|
62
|
+
}
|
|
63
|
+
return d;
|
|
64
|
+
}
|
|
65
|
+
function b(e, t) {
|
|
66
|
+
const n = [];
|
|
67
|
+
let r = "", o = !1;
|
|
68
|
+
for (let i = 0; i < e.length; i++) {
|
|
69
|
+
const a = e[i], s = e[i + 1];
|
|
70
|
+
a === '"' ? o && s === '"' ? (r += '"', i++) : o = !o : a === t && !o ? (n.push(r.trim()), r = "") : r += a;
|
|
71
|
+
}
|
|
72
|
+
return n.push(r.trim()), n;
|
|
73
|
+
}
|
|
74
|
+
async function k(e) {
|
|
75
|
+
const t = await p(e, "text");
|
|
76
|
+
try {
|
|
77
|
+
return JSON.parse(t);
|
|
78
|
+
} catch (n) {
|
|
79
|
+
throw new Error(`JSON 解析失败:${n instanceof Error ? n.message : "未知错误"}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function F(e, t, n) {
|
|
83
|
+
try {
|
|
84
|
+
const r = await fetch(e, n?.fetchOptions);
|
|
85
|
+
if (!r.ok)
|
|
86
|
+
throw new Error(`下载失败:${r.status} ${r.statusText}`);
|
|
87
|
+
const o = await r.blob();
|
|
88
|
+
let i = t;
|
|
89
|
+
if (!i) {
|
|
90
|
+
const a = r.headers.get("Content-Disposition");
|
|
91
|
+
if (a) {
|
|
92
|
+
const s = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/.exec(a);
|
|
93
|
+
s && s[1] && (i = decodeURIComponent(s[1].replace(/['"]/g, "")));
|
|
94
|
+
}
|
|
95
|
+
i || (i = e.split("/").pop() || "download");
|
|
96
|
+
}
|
|
97
|
+
g(o, i, n);
|
|
98
|
+
} catch (r) {
|
|
99
|
+
throw console.error("文件下载失败:", r), r;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function g(e, t, n) {
|
|
103
|
+
const r = URL.createObjectURL(e), o = document.createElement("a");
|
|
104
|
+
o.href = r, o.download = t, n?.newWindow && (o.target = "_blank"), document.body.appendChild(o), o.click(), document.body.removeChild(o), URL.revokeObjectURL(r);
|
|
105
|
+
}
|
|
106
|
+
function $(e, t, n) {
|
|
107
|
+
e.startsWith("data:") ? (n = e.split(",")[0].split(":")[1].split(";")[0], e = e.split(",")[1]) : n || (n = "application/octet-stream");
|
|
108
|
+
const o = atob(e), i = new Array(o.length);
|
|
109
|
+
for (let d = 0; d < o.length; d++)
|
|
110
|
+
i[d] = o.charCodeAt(d);
|
|
111
|
+
const a = new Uint8Array(i), s = new Blob([a], { type: n });
|
|
112
|
+
g(s, t);
|
|
113
|
+
}
|
|
114
|
+
async function I(e, t = 500) {
|
|
115
|
+
for (let n = 0; n < e.length; n++)
|
|
116
|
+
try {
|
|
117
|
+
await F(e[n]), n < e.length - 1 && await new Promise((r) => setTimeout(r, t));
|
|
118
|
+
} catch (r) {
|
|
119
|
+
console.error(`第 ${n + 1} 个文件下载失败:`, r);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function L(e) {
|
|
123
|
+
return p(e, "dataURL");
|
|
124
|
+
}
|
|
125
|
+
function O(e, t) {
|
|
126
|
+
e.startsWith("data:") ? (t = e.split(",")[0].split(":")[1].split(";")[0], e = e.split(",")[1]) : t || (t = "application/octet-stream");
|
|
127
|
+
const r = atob(e), o = new Array(r.length);
|
|
128
|
+
for (let a = 0; a < r.length; a++)
|
|
129
|
+
o[a] = r.charCodeAt(a);
|
|
130
|
+
const i = new Uint8Array(o);
|
|
131
|
+
return new Blob([i], { type: t });
|
|
132
|
+
}
|
|
133
|
+
function R(e, t, n = "utf-8") {
|
|
134
|
+
const r = new Blob([e], { type: `text/plain;charset=${n}` });
|
|
135
|
+
g(r, t);
|
|
136
|
+
}
|
|
137
|
+
function w(e, t) {
|
|
138
|
+
if (e == null)
|
|
139
|
+
return "";
|
|
140
|
+
const n = String(e);
|
|
141
|
+
return n.includes(t) || n.includes('"') || n.includes(`
|
|
142
|
+
`) || n.includes("\r") ? `"${n.replace(/"/g, '""')}"` : n;
|
|
143
|
+
}
|
|
144
|
+
function T(e, t, n = {}) {
|
|
145
|
+
const {
|
|
146
|
+
separator: r = ",",
|
|
147
|
+
includeHeader: o = !0,
|
|
148
|
+
encoding: i = "utf-8"
|
|
149
|
+
} = n;
|
|
150
|
+
if (e.length === 0)
|
|
151
|
+
throw new Error("数据不能为空");
|
|
152
|
+
let a = "";
|
|
153
|
+
if (typeof e[0] == "object" && !Array.isArray(e[0])) {
|
|
154
|
+
const l = e, u = Array.from(
|
|
155
|
+
new Set(l.flatMap((c) => Object.keys(c)))
|
|
156
|
+
);
|
|
157
|
+
o && (a += u.join(r) + `
|
|
158
|
+
`), l.forEach((c) => {
|
|
159
|
+
const f = u.map((x) => {
|
|
160
|
+
const C = c[x];
|
|
161
|
+
return w(C, r);
|
|
162
|
+
});
|
|
163
|
+
a += f.join(r) + `
|
|
164
|
+
`;
|
|
165
|
+
});
|
|
166
|
+
} else {
|
|
167
|
+
const l = e;
|
|
168
|
+
if (o && l.length > 0) {
|
|
169
|
+
const u = l[0].map(
|
|
170
|
+
(c) => w(c, r)
|
|
171
|
+
);
|
|
172
|
+
a += u.join(r) + `
|
|
173
|
+
`;
|
|
174
|
+
for (let c = 1; c < l.length; c++) {
|
|
175
|
+
const f = l[c].map(
|
|
176
|
+
(x) => w(x, r)
|
|
177
|
+
);
|
|
178
|
+
a += f.join(r) + `
|
|
179
|
+
`;
|
|
180
|
+
}
|
|
181
|
+
} else o || l.forEach((u) => {
|
|
182
|
+
const c = u.map(
|
|
183
|
+
(f) => w(f, r)
|
|
184
|
+
);
|
|
185
|
+
a += c.join(r) + `
|
|
186
|
+
`;
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
a = a.trimEnd();
|
|
190
|
+
const d = "\uFEFF", h = new Blob([d + a], {
|
|
191
|
+
type: `text/csv;charset=${i}`
|
|
192
|
+
});
|
|
193
|
+
g(h, t);
|
|
194
|
+
}
|
|
195
|
+
function z(e, t, n = {}) {
|
|
196
|
+
const {
|
|
197
|
+
pretty: r = !0,
|
|
198
|
+
spaces: o = 2,
|
|
199
|
+
encoding: i = "utf-8"
|
|
200
|
+
} = n;
|
|
201
|
+
try {
|
|
202
|
+
const a = r ? JSON.stringify(e, null, o) : JSON.stringify(e), s = new Blob([a], {
|
|
203
|
+
type: `application/json;charset=${i}`
|
|
204
|
+
});
|
|
205
|
+
g(s, t);
|
|
206
|
+
} catch (a) {
|
|
207
|
+
throw console.error("JSON 序列化失败:", a), new Error("数据无法序列化为 JSON");
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function y(e) {
|
|
211
|
+
const t = typeof e == "string" ? e : e.name, n = t.lastIndexOf(".");
|
|
212
|
+
return n === -1 || n === t.length - 1 ? "" : t.slice(n).toLowerCase();
|
|
213
|
+
}
|
|
214
|
+
function U(e) {
|
|
215
|
+
const t = typeof e == "string" ? e : e.name, n = t.lastIndexOf(".");
|
|
216
|
+
return n === -1 ? t : t.slice(0, n);
|
|
217
|
+
}
|
|
218
|
+
function j(e) {
|
|
219
|
+
return {
|
|
220
|
+
name: e.name,
|
|
221
|
+
size: e.size,
|
|
222
|
+
type: e.type,
|
|
223
|
+
lastModified: e.lastModified
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
function v(e, t) {
|
|
227
|
+
if (!e || !t || t.length === 0)
|
|
228
|
+
return !1;
|
|
229
|
+
const n = e.type.toLowerCase(), r = y(e).toLowerCase();
|
|
230
|
+
return t.some((o) => {
|
|
231
|
+
const i = o.toLowerCase();
|
|
232
|
+
if (i.endsWith("/*")) {
|
|
233
|
+
const a = i.split("/")[0];
|
|
234
|
+
return n.startsWith(`${a}/`);
|
|
235
|
+
}
|
|
236
|
+
return i.startsWith(".") ? r === i : n === i;
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function E(e, t) {
|
|
240
|
+
return e ? e.size <= t : !1;
|
|
241
|
+
}
|
|
242
|
+
function m(e) {
|
|
243
|
+
if (!e)
|
|
244
|
+
return !1;
|
|
245
|
+
if (e.type.startsWith("image/"))
|
|
246
|
+
return !0;
|
|
247
|
+
const t = [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg", ".ico"], n = y(e);
|
|
248
|
+
return t.includes(n);
|
|
249
|
+
}
|
|
250
|
+
function B(e) {
|
|
251
|
+
return new Promise((t, n) => {
|
|
252
|
+
if (!m(e)) {
|
|
253
|
+
n(new Error("文件不是有效的图片格式"));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const r = new FileReader();
|
|
257
|
+
r.onload = (o) => {
|
|
258
|
+
const i = new Image();
|
|
259
|
+
i.onload = () => {
|
|
260
|
+
t({
|
|
261
|
+
width: i.width,
|
|
262
|
+
height: i.height
|
|
263
|
+
});
|
|
264
|
+
}, i.onerror = () => {
|
|
265
|
+
n(new Error("图片加载失败"));
|
|
266
|
+
}, i.src = o.target?.result;
|
|
267
|
+
}, r.onerror = () => {
|
|
268
|
+
n(new Error("文件读取失败"));
|
|
269
|
+
}, r.readAsDataURL(e);
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
async function H(e, t = {}) {
|
|
273
|
+
const n = [];
|
|
274
|
+
if (t.acceptTypes && t.acceptTypes.length > 0 && (v(e, t.acceptTypes) || n.push(`不支持的文件类型。接受:${t.acceptTypes.join(", ")}`)), t.maxSize !== void 0 && !E(e, t.maxSize)) {
|
|
275
|
+
const r = A(t.maxSize);
|
|
276
|
+
n.push(`文件过大。最大允许:${r}`);
|
|
277
|
+
}
|
|
278
|
+
if (t.mustBeImage && !m(e) && n.push("文件必须是图片格式"), m(e) && (t.minWidth !== void 0 || t.maxWidth !== void 0 || t.minHeight !== void 0 || t.maxHeight !== void 0))
|
|
279
|
+
try {
|
|
280
|
+
const r = await B(e);
|
|
281
|
+
t.minWidth !== void 0 && r.width < t.minWidth && n.push(`图片宽度过小。最小宽度:${t.minWidth}px`), t.maxWidth !== void 0 && r.width > t.maxWidth && n.push(`图片宽度过大。最大宽度:${t.maxWidth}px`), t.minHeight !== void 0 && r.height < t.minHeight && n.push(`图片高度过小。最小高度:${t.minHeight}px`), t.maxHeight !== void 0 && r.height > t.maxHeight && n.push(`图片高度过大。最大高度:${t.maxHeight}px`);
|
|
282
|
+
} catch {
|
|
283
|
+
n.push("无法获取图片尺寸");
|
|
284
|
+
}
|
|
285
|
+
return {
|
|
286
|
+
valid: n.length === 0,
|
|
287
|
+
errors: n
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function A(e, t = 2) {
|
|
291
|
+
if (e === 0) return "0 B";
|
|
292
|
+
const n = ["B", "KB", "MB", "GB", "TB"], r = 1024, o = Math.floor(Math.log(e) / Math.log(r));
|
|
293
|
+
return parseFloat((e / Math.pow(r, o)).toFixed(t)) + " " + n[o];
|
|
294
|
+
}
|
|
295
|
+
const J = {
|
|
296
|
+
// 读取
|
|
297
|
+
readFile: p,
|
|
298
|
+
readTxtFile: S,
|
|
299
|
+
readCsvFile: W,
|
|
300
|
+
readJsonFile: k,
|
|
301
|
+
// 下载
|
|
302
|
+
downloadFile: F,
|
|
303
|
+
downloadBlob: g,
|
|
304
|
+
downloadBase64: $,
|
|
305
|
+
downloadMultiple: I,
|
|
306
|
+
// 转换
|
|
307
|
+
fileToBase64: L,
|
|
308
|
+
base64ToBlob: O,
|
|
309
|
+
// 生成
|
|
310
|
+
generateTxtFile: R,
|
|
311
|
+
generateCsvFile: T,
|
|
312
|
+
generateJsonFile: z,
|
|
313
|
+
// 验证
|
|
314
|
+
checkFileType: v,
|
|
315
|
+
checkFileSize: E,
|
|
316
|
+
isImage: m,
|
|
317
|
+
getImageDimensions: B,
|
|
318
|
+
validateFile: H,
|
|
319
|
+
formatFileSize: A,
|
|
320
|
+
// 工具
|
|
321
|
+
getFileExtension: y,
|
|
322
|
+
getFileNameWithoutExtension: U,
|
|
323
|
+
getFileInfo: j
|
|
324
|
+
};
|
|
325
|
+
export {
|
|
326
|
+
O as base64ToBlob,
|
|
327
|
+
E as checkFileSize,
|
|
328
|
+
v as checkFileType,
|
|
329
|
+
J as default,
|
|
330
|
+
$ as downloadBase64,
|
|
331
|
+
g as downloadBlob,
|
|
332
|
+
F as downloadFile,
|
|
333
|
+
I as downloadMultiple,
|
|
334
|
+
L as fileToBase64,
|
|
335
|
+
A as formatFileSize,
|
|
336
|
+
T as generateCsvFile,
|
|
337
|
+
z as generateJsonFile,
|
|
338
|
+
R as generateTxtFile,
|
|
339
|
+
y as getFileExtension,
|
|
340
|
+
j as getFileInfo,
|
|
341
|
+
U as getFileNameWithoutExtension,
|
|
342
|
+
B as getImageDimensions,
|
|
343
|
+
m as isImage,
|
|
344
|
+
W as readCsvFile,
|
|
345
|
+
p as readFile,
|
|
346
|
+
k as readJsonFile,
|
|
347
|
+
S as readTxtFile,
|
|
348
|
+
H as validateFile
|
|
349
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@giszhc/file-utils",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"types"
|
|
8
|
+
],
|
|
9
|
+
"module": "dist/file-utils.js",
|
|
10
|
+
"types": "types/index.d.ts",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/giszhc/file-utils.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/giszhc/file-utils/issues"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"file",
|
|
23
|
+
"download"
|
|
24
|
+
],
|
|
25
|
+
"homepage": "https://github.com/giszhc/file-utils#readme",
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"typescript": "~5.9.3",
|
|
28
|
+
"vite": "^7.2.4"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"dev": "vite",
|
|
32
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
33
|
+
"build": "pnpm run build:types && vite build",
|
|
34
|
+
"preview": "vite preview"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文件转换相关方法
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 将 File 或 Blob 对象转换为 Base64 编码
|
|
6
|
+
*
|
|
7
|
+
* @param file - File 或 Blob 对象
|
|
8
|
+
* @returns Promise<string> - Base64 编码的字符串(包含 data URL 前缀)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // 在文件上传前预览
|
|
12
|
+
* const input = document.querySelector('input[type="file"]');
|
|
13
|
+
* input.addEventListener('change', async (e) => {
|
|
14
|
+
* const file = e.target.files[0];
|
|
15
|
+
* const base64 = await fileToBase64(file);
|
|
16
|
+
* console.log(base64); // data:image/jpeg;base64,/9j/4AAQSkZJRg...
|
|
17
|
+
* });
|
|
18
|
+
*/
|
|
19
|
+
export declare function fileToBase64(file: File | Blob): Promise<string>;
|
|
20
|
+
/**
|
|
21
|
+
* 将 Base64 编码转换为 Blob 对象
|
|
22
|
+
*
|
|
23
|
+
* @param base64 - Base64 编码的字符串(可以包含或不包含 data URL 前缀)
|
|
24
|
+
* @param mimeType - MIME 类型(可选),如果未指定且 base64 不包含前缀,默认为 'application/octet-stream'
|
|
25
|
+
* @returns Blob - 转换后的 Blob 对象
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* // 转换带前缀的 Base64
|
|
29
|
+
* const base64 = 'data:image/png;base64,iVBORw0KGgoAAAANS...';
|
|
30
|
+
* const blob = base64ToBlob(base64);
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // 转换不带前缀的 Base64
|
|
34
|
+
* const base64 = 'iVBORw0KGgoAAAANS...';
|
|
35
|
+
* const blob = base64ToBlob(base64, 'image/png');
|
|
36
|
+
*/
|
|
37
|
+
export declare function base64ToBlob(base64: string, mimeType?: string): Blob;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文件下载相关方法
|
|
3
|
+
*/
|
|
4
|
+
import type { DownloadOptions } from './types';
|
|
5
|
+
/**
|
|
6
|
+
* 从 URL 下载文件
|
|
7
|
+
*
|
|
8
|
+
* @param url - 文件的 URL 地址
|
|
9
|
+
* @param filename - 保存的文件名(可选),如果不指定则尝试从 URL 中提取
|
|
10
|
+
* @param options - 下载选项配置(可选)
|
|
11
|
+
*
|
|
12
|
+
* @returns Promise<void>
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // 下载文件并指定文件名
|
|
16
|
+
* await downloadFile('https://example.com/file.pdf', 'my-file.pdf');
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // 使用默认文件名
|
|
20
|
+
* await downloadFile('https://example.com/image.jpg');
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // 设置授权请求头
|
|
24
|
+
* await downloadFile('https://api.example.com/file/123', undefined, {
|
|
25
|
+
* fetchOptions: {
|
|
26
|
+
* headers: {
|
|
27
|
+
* 'Authorization': 'Bearer token123'
|
|
28
|
+
* }
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // 使用 POST 请求下载
|
|
34
|
+
* await downloadFile('https://api.example.com/download', 'file.pdf', {
|
|
35
|
+
* fetchOptions: {
|
|
36
|
+
* method: 'POST',
|
|
37
|
+
* body: JSON.stringify({ fileId: 123 })
|
|
38
|
+
* }
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* @remarks
|
|
42
|
+
* - 需要目标服务器支持 CORS(跨域资源共享)
|
|
43
|
+
* - 会自动清理临时创建的 Blob URL
|
|
44
|
+
* - 可以通过 fetchOptions 传入自定义的 fetch 配置
|
|
45
|
+
*/
|
|
46
|
+
export declare function downloadFile(url: string, filename?: string, options?: DownloadOptions): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* 下载 Blob 对象
|
|
49
|
+
*
|
|
50
|
+
* @param blob - Blob 对象
|
|
51
|
+
* @param filename - 保存的文件名(包含扩展名)
|
|
52
|
+
* @param options - 下载选项配置(可选)
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // 下载文本文件
|
|
56
|
+
* const blob = new Blob(['Hello World'], { type: 'text/plain' });
|
|
57
|
+
* downloadBlob(blob, 'hello.txt');
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* // 下载图片
|
|
61
|
+
* const blob = await fetch('https://example.com/image.jpg').then(r => r.blob());
|
|
62
|
+
* downloadBlob(blob, 'image.jpg');
|
|
63
|
+
*/
|
|
64
|
+
export declare function downloadBlob(blob: Blob, filename: string, options?: DownloadOptions): void;
|
|
65
|
+
/**
|
|
66
|
+
* 下载 Base64 编码的文件
|
|
67
|
+
*
|
|
68
|
+
* @param base64 - Base64 编码的字符串(可以包含或不包含 data:image/png;base64, 前缀)
|
|
69
|
+
* @param filename - 保存的文件名(包含扩展名)
|
|
70
|
+
* @param mimeType - MIME 类型(可选),如果 base64 不包含前缀且未指定此参数,默认为 'application/octet-stream'
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // 下载 PNG 图片
|
|
74
|
+
* const base64Data = 'data:image/png;base64,iVBORw0KGgoAAAANS...';
|
|
75
|
+
* downloadBase64(base64Data, 'image.png');
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* // 下载不带前缀的 Base64 数据
|
|
79
|
+
* const base64Data = 'iVBORw0KGgoAAAANS...';
|
|
80
|
+
* downloadBase64(base64Data, 'image.png', 'image/png');
|
|
81
|
+
*/
|
|
82
|
+
export declare function downloadBase64(base64: string, filename: string, mimeType?: string): void;
|
|
83
|
+
/**
|
|
84
|
+
* 批量下载文件
|
|
85
|
+
*
|
|
86
|
+
* @param urls - URL 数组
|
|
87
|
+
* @param delay - 下载间隔时间(毫秒),默认 500ms,避免浏览器拦截
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* const urls = [
|
|
91
|
+
* 'https://example.com/image1.jpg',
|
|
92
|
+
* 'https://example.com/image2.jpg'
|
|
93
|
+
* ];
|
|
94
|
+
* downloadMultiple(urls, 1000); // 每隔 1 秒下载一个
|
|
95
|
+
*/
|
|
96
|
+
export declare function downloadMultiple(urls: string[], delay?: number): Promise<void>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 文件生成相关方法
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* 生成并下载 TXT 文件
|
|
6
|
+
*
|
|
7
|
+
* @param content - 文本内容
|
|
8
|
+
* @param filename - 文件名(包含 .txt 扩展名)
|
|
9
|
+
* @param encoding - 字符编码,默认 'utf-8'
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // 生成简单的文本文件
|
|
13
|
+
* generateTxtFile('Hello World!', 'hello.txt');
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // 生成多行文本
|
|
17
|
+
* const lines = ['第一行', '第二行', '第三行'].join('\n');
|
|
18
|
+
* generateTxtFile(lines, 'multiline.txt');
|
|
19
|
+
*/
|
|
20
|
+
export declare function generateTxtFile(content: string, filename: string, encoding?: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* 生成并下载 CSV 文件
|
|
23
|
+
*
|
|
24
|
+
* @param data - 数据数组(对象数组或二维数组)
|
|
25
|
+
* @param filename - 文件名(包含 .csv 扩展名)
|
|
26
|
+
* @param options - CSV 选项配置(可选)
|
|
27
|
+
* - separator: 字段分隔符,默认 ','
|
|
28
|
+
* - includeHeader: 是否包含表头,默认 true
|
|
29
|
+
* - encoding: 字符编码,默认 'utf-8'
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* // 使用对象数组生成 CSV
|
|
33
|
+
* const users = [
|
|
34
|
+
* { name: '张三', age: 25, city: '北京' },
|
|
35
|
+
* { name: '李四', age: 30, city: '上海' },
|
|
36
|
+
* { name: '王五', age: 28, city: '广州' }
|
|
37
|
+
* ];
|
|
38
|
+
* generateCsvFile(users, 'users.csv');
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* // 使用二维数组生成 CSV
|
|
42
|
+
* const data = [
|
|
43
|
+
* ['姓名', '年龄', '城市'],
|
|
44
|
+
* ['张三', 25, '北京'],
|
|
45
|
+
* ['李四', 30, '上海']
|
|
46
|
+
* ];
|
|
47
|
+
* generateCsvFile(data, 'data.csv');
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* // 自定义分隔符(制表符)
|
|
51
|
+
* generateCsvFile(data, 'data.tsv', { separator: '\t' });
|
|
52
|
+
*/
|
|
53
|
+
export declare function generateCsvFile(data: Record<string, any>[] | any[][], filename: string, options?: {
|
|
54
|
+
separator?: string;
|
|
55
|
+
includeHeader?: boolean;
|
|
56
|
+
encoding?: string;
|
|
57
|
+
}): void;
|
|
58
|
+
/**
|
|
59
|
+
* 生成并下载 JSON 文件
|
|
60
|
+
*
|
|
61
|
+
* @param data - JavaScript 对象或数组
|
|
62
|
+
* @param filename - 文件名(包含 .json 扩展名)
|
|
63
|
+
* @param options - JSON 选项配置(可选)
|
|
64
|
+
* - pretty: 是否格式化输出,默认 true
|
|
65
|
+
* - spaces: 缩进空格数,默认 2
|
|
66
|
+
* - encoding: 字符编码,默认 'utf-8'
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* // 生成简单的 JSON 文件
|
|
70
|
+
* const data = { name: '张三', age: 25 };
|
|
71
|
+
* generateJsonFile(data, 'user.json');
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* // 生成格式化的 JSON 数组
|
|
75
|
+
* const users = [
|
|
76
|
+
* { name: '张三', age: 25 },
|
|
77
|
+
* { name: '李四', age: 30 }
|
|
78
|
+
* ];
|
|
79
|
+
* generateJsonFile(users, 'users.json');
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* // 压缩输出(不格式化)
|
|
83
|
+
* generateJsonFile(data, 'data.min.json', { pretty: false });
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* // 自定义缩进
|
|
87
|
+
* generateJsonFile(data, 'data.json', { spaces: 4 });
|
|
88
|
+
*/
|
|
89
|
+
export declare function generateJsonFile(data: any, filename: string, options?: {
|
|
90
|
+
pretty?: boolean;
|
|
91
|
+
spaces?: number;
|
|
92
|
+
encoding?: string;
|
|
93
|
+
}): void;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* file-utils 文件操作工具库
|
|
3
|
+
*
|
|
4
|
+
* 提供常用的文件处理功能:读取、下载、转换、生成、验证等
|
|
5
|
+
* 支持 Tree Shaking,按需引入
|
|
6
|
+
*/
|
|
7
|
+
export type { ReadFileType, CompressOptions, DownloadOptions, IFileInfo, IValidationResult, IFileValidationOptions } from './types';
|
|
8
|
+
export { readFile, readTxtFile, readCsvFile, readJsonFile } from './read';
|
|
9
|
+
export { downloadFile, downloadBlob, downloadBase64, downloadMultiple } from './download';
|
|
10
|
+
export { fileToBase64, base64ToBlob } from './convert';
|
|
11
|
+
export { generateTxtFile, generateCsvFile, generateJsonFile } from './generate';
|
|
12
|
+
export { checkFileType, checkFileSize, isImage, getImageDimensions, validateFile, formatFileSize } from './validators';
|
|
13
|
+
export { getFileExtension, getFileNameWithoutExtension, getFileInfo } from './utils';
|
|
14
|
+
import { readFile, readTxtFile, readCsvFile, readJsonFile } from './read';
|
|
15
|
+
import { downloadFile, downloadBlob, downloadBase64, downloadMultiple } from './download';
|
|
16
|
+
import { fileToBase64, base64ToBlob } from './convert';
|
|
17
|
+
import { generateTxtFile, generateCsvFile, generateJsonFile } from './generate';
|
|
18
|
+
import { checkFileType, checkFileSize, isImage, getImageDimensions, validateFile, formatFileSize } from './validators';
|
|
19
|
+
import { getFileExtension, getFileNameWithoutExtension, getFileInfo } from './utils';
|
|
20
|
+
declare const _default: {
|
|
21
|
+
readFile: typeof readFile;
|
|
22
|
+
readTxtFile: typeof readTxtFile;
|
|
23
|
+
readCsvFile: typeof readCsvFile;
|
|
24
|
+
readJsonFile: typeof readJsonFile;
|
|
25
|
+
downloadFile: typeof downloadFile;
|
|
26
|
+
downloadBlob: typeof downloadBlob;
|
|
27
|
+
downloadBase64: typeof downloadBase64;
|
|
28
|
+
downloadMultiple: typeof downloadMultiple;
|
|
29
|
+
fileToBase64: typeof fileToBase64;
|
|
30
|
+
base64ToBlob: typeof base64ToBlob;
|
|
31
|
+
generateTxtFile: typeof generateTxtFile;
|
|
32
|
+
generateCsvFile: typeof generateCsvFile;
|
|
33
|
+
generateJsonFile: typeof generateJsonFile;
|
|
34
|
+
checkFileType: typeof checkFileType;
|
|
35
|
+
checkFileSize: typeof checkFileSize;
|
|
36
|
+
isImage: typeof isImage;
|
|
37
|
+
getImageDimensions: typeof getImageDimensions;
|
|
38
|
+
validateFile: typeof validateFile;
|
|
39
|
+
formatFileSize: typeof formatFileSize;
|
|
40
|
+
getFileExtension: typeof getFileExtension;
|
|
41
|
+
getFileNameWithoutExtension: typeof getFileNameWithoutExtension;
|
|
42
|
+
getFileInfo: typeof getFileInfo;
|
|
43
|
+
};
|
|
44
|
+
export default _default;
|