1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
CREATE OR REPLACE PACKAGE UploadFilePackageV2 AS
-- 依据上传的页项生成hash文件名和源文件名
PROCEDURE GenerateHashFileName( P_FileItem IN VARCHAR2,
O_HashFileName OUT varchar2,
O_FileName OUT varchar2 );
-- 将blob数据写成磁盘文件
PROCEDURE WriteBlobToUploadFile( P_HashFileName IN VARCHAR2,
P_FileBlob IN BLOB,
P_DirObject IN VARCHAR2 );
-- 读磁盘文件返回blob
FUNCTION ReadUploadFileToBlob( P_HashFileName IN varchar2,
P_DirObject IN VARCHAR2 ) RETURN blob;
-- 依据blob 发起apex 下载附件
PROCEDURE blobToDownload( P_FileName IN VARCHAR2,
p_blob IN blob,
P_MimeType IN VARCHAR2 DEFAULT 'text/plain' ) ;
-- 从磁盘读取blob 并换气APEX下载
PROCEDURE ReadUploadFileToDownload(
P_FileName IN VARCHAR2,
P_HashFileName IN varchar2,
P_DirObject IN VARCHAR2,
P_MimeType IN VARCHAR2 DEFAULT 'text/plain' );
-- 从磁盘删除文件
PROCEDURE DeleteUploadFile( P_HashFileName IN VARCHAR2,
P_DirObject IN VARCHAR2 );
END UploadFilePackageV2;
CREATE OR REPLACE PACKAGE BODY UploadFilePackageV2 AS
PROCEDURE GenerateHashFileName( P_FileItem IN VARCHAR2,
O_HashFileName OUT varchar2,
O_FileName OUT varchar2 )
IS
ex_no_data_found_file_item EXCEPTION;
v_file_type varchar2(200);
BEGIN
-- 检查是否为空
IF P_Fileitem IS NULL THEN
RAISE ex_no_data_found_file_item ;
END IF;
-- 获取上传的文件名
O_FileName := SUBSTR(P_Fileitem, INSTR(P_Fileitem, '/') + 1, LENGTH(P_Fileitem));
v_file_type := SUBSTR(O_FileName, INSTR(O_FileName, '.', -1));
-- 根据上传的文件名 获取hash后的名字
O_HashFileName := SYS.DBMS_CRYPTO.HASH(UTL_I18N.STRING_TO_RAW(O_FileName,
'AL32UTF8'),
DBMS_CRYPTO.HASH_SH1) || SYS_GUID() || v_file_type;
-- O_HashFileName := SYS_GUID();
EXCEPTION
WHEN ex_no_data_found_file_item THEN
RAISE_APPLICATION_ERROR(-20001, '请检查上传对象.');
END GenerateHashFileName;
PROCEDURE WriteBlobToUploadFile( P_HashFileName IN VARCHAR2,
P_FileBlob IN BLOB,
P_DirObject IN VARCHAR2 )
IS
v_buffer RAW(32767);
blob_length INTEGER;
out_file UTL_FILE.FILE_TYPE;
chunk_size BINARY_INTEGER := 32767;
blob_position INTEGER := 1;
ex_no_data_found_blob EXCEPTION;
BEGIN
apex_debug.message('--------UploadFileName-------');
apex_debug.message(P_HashFileName);
IF P_FileBlob IS NULL THEN
RAISE ex_no_data_found_blob;
END IF;
-- 检索BLOB的大小
blob_length := DBMS_LOB.GETLENGTH(P_FileBlob);
-- 打开要写入blob的位置的句柄
-- 注意:“wb”参数表示“以字节模式写入”,并且只有可在UTL_FILE pkg中使用Oracle 10g或更高版本。
-- 使用'w'代替pre Oracle 10q数据库。
out_file := UTL_FILE.FOPEN(P_DirObject,
P_HashFileName,
'wb',
chunk_size);
-- 将BLOB以块的形式写入文件
WHILE blob_position <= blob_length
LOOP
IF ((blob_position + chunk_size - 1) > blob_length) THEN
chunk_size := blob_length - blob_position + 1;
END IF;
dbms_lob.read(P_FileBlob, chunk_size, blob_position, v_buffer);
UTL_FILE.put_raw(out_file, v_buffer, TRUE);
blob_position := blob_position + chunk_size;
END LOOP;
UTL_FILE.FCLOSE(out_file);
EXCEPTION
WHEN ex_no_data_found_blob THEN
RAISE_APPLICATION_ERROR(-20000, '请检查文件对象。');
WHEN utl_file.invalid_path THEN
RAISE_APPLICATION_ERROR(-20011, 'INVALID_PATH: 文件位置或文件名无效。');
IF UTL_FILE.IS_OPEN(out_file) THEN
UTL_FILE.FCLOSE(out_file);
END IF;
WHEN utl_file.invalid_mode THEN
RAISE_APPLICATION_ERROR(-20022, 'INVALID_MODE: FOPEN中的open_mode参数无效。');
IF UTL_FILE.IS_OPEN(out_file) THEN
UTL_FILE.FCLOSE(out_file);
END IF;
WHEN utl_file.invalid_filehandle THEN
RAISE_APPLICATION_ERROR(-20022, 'INVALID_FILEHANDLE: 文件句柄无效。');
IF UTL_FILE.IS_OPEN(out_file) THEN
UTL_FILE.FCLOSE(out_file);
END IF;
WHEN utl_file.invalid_operation THEN
RAISE_APPLICATION_ERROR(-20033, 'INVALID_OPERATION: 文件无法打开或按要求操作。');
IF UTL_FILE.IS_OPEN(out_file) THEN
UTL_FILE.FCLOSE(out_file);
END IF;
WHEN utl_file.read_error THEN
RAISE_APPLICATION_ERROR(-20044, 'READ_ERROR: 期间发生操作系统错误读操作。');
IF UTL_FILE.IS_OPEN(out_file) THEN
UTL_FILE.FCLOSE(out_file);
END IF;
WHEN utl_file.write_error THEN
RAISE_APPLICATION_ERROR(-20055, 'WRITE_ERROR: :操作系统错误写操作。');
IF UTL_FILE.IS_OPEN(out_file) THEN
UTL_FILE.FCLOSE(out_file);
END IF;
WHEN utl_file.internal_error THEN
RAISE_APPLICATION_ERROR(-20066, 'INTERNAL_ERROR: PL/SQL中未指定的错误。');
IF UTL_FILE.IS_OPEN(out_file) THEN
UTL_FILE.FCLOSE(out_file);
END IF;
END WriteBlobToUploadFile;
FUNCTION ReadUploadFileToBlob( P_HashFileName IN varchar2,
P_DirObject IN VARCHAR2 ) RETURN blob
IS
v_lob BLOB;
v_BFile BFILE;
v_lenght number;
v_src_offset NUMBER := 1;
v_dest_offset NUMBER := 1;
BEGIN
/**********************************************************************************************************************************
2024/03/11 14:33
依据文件名,读磁盘上的文件并返回二进制数据blob
**********************************************************************************************************************************/
dbms_lob.createtemporary(v_lob, FALSE, DBMS_LOB.SESSION);
v_BFile := BFILENAME(P_DirObject, P_HashFileName);
v_lenght := DBMS_LOB.GETLENGTH(v_BFile);
dbms_lob.fileOpen(v_BFile);
dbms_lob.loadblobfromfile(dest_lob => v_lob,
src_bfile => v_BFile,
amount => v_lenght,
dest_offset => v_dest_offset,
src_offset => v_src_offset);
dbms_lob.fileClose(v_BFile);
RETURN v_lob;
EXCEPTION
WHEN utl_file.invalid_path THEN
RAISE_APPLICATION_ERROR(-20011, 'INVALID_PATH: 文件位置或文件名无效。');
WHEN utl_file.invalid_mode THEN
RAISE_APPLICATION_ERROR(-20022, 'INVALID_MODE: FOPEN中的open_mode参数无效。');
WHEN utl_file.invalid_filehandle THEN
RAISE_APPLICATION_ERROR(-20022, 'INVALID_FILEHANDLE: 文件句柄无效。');
WHEN utl_file.invalid_operation THEN
RAISE_APPLICATION_ERROR(-20033, 'INVALID_OPERATION: 文件无法打开或按要求操作。');
WHEN utl_file.read_error THEN
RAISE_APPLICATION_ERROR(-20044, 'READ_ERROR: 期间发生操作系统错误读操作。');
WHEN utl_file.write_error THEN
RAISE_APPLICATION_ERROR(-20055, 'WRITE_ERROR: :操作系统错误写操作。');
WHEN utl_file.internal_error THEN
RAISE_APPLICATION_ERROR(-20066, 'INTERNAL_ERROR: PL/SQL中未指定的错误。');
END ReadUploadFileToBlob ;
PROCEDURE blobToDownload( P_FileName IN VARCHAR2,
p_blob IN blob,
P_MimeType IN VARCHAR2 DEFAULT 'text/plain' )
IS
v_lob BLOB := p_blob;
BEGIN
-- download file
htp.init;
-- https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
owa_util.mime_header(P_MimeType, FALSE);
-- htp.p('Content-Type: text/html; charset=utf-8' );
htp.p('Content-length: ' || sys.dbms_lob.getlength(v_lob));
-- htp.p('Content-Disposition: attachment; filename="' || P_FileName || '"');
htp.p(q'~Content-Disposition: attachment; filename*=UTF-8''~' || utl_url.escape(P_FileName, TRUE, 'UTF-8'));
--2023-07-12
-- htp.p('Cache-Control: max-age=3600'); -- 浏览器缓存一个小时,根据需要进行调整
owa_util.http_header_close;
wpg_docload.download_file(v_lob);
apex_application.stop_apex_engine;
END blobToDownload ;
PROCEDURE ReadUploadFileToDownload( P_FileName IN VARCHAR2,
P_HashFileName IN varchar2,
P_DirObject IN VARCHAR2,
P_MimeType IN varchar2 DEFAULT 'text/plain' )
IS
v_lob BLOB;
v_BFile BFILE;
v_src_offset NUMBER := 1;
v_dest_offset NUMBER := 1;
BEGIN
v_lob := ReadUploadFileToBlob(P_HashFileName=>P_HashFileName,
P_DirObject=>P_DirObject);
blobToDownload(P_FileName=>P_FileName,
p_blob => v_lob,
P_MimeType=>P_MimeType);
END ReadUploadFileToDownload;
PROCEDURE DeleteUploadFile( P_HashFileName IN VARCHAR2, P_DirObject IN VARCHAR2 )
IS
BEGIN
UTL_FILE.FREMOVE(P_DirObject, P_HashFileName);
EXCEPTION
-- WHEN utl_file.invalid_path THEN
-- RAISE_APPLICATION_ERROR(-20011, 'INVALID_PATH: 文件位置或文件名无效。');
--- WHEN utl_file.invalid_mode THEN
-- RAISE_APPLICATION_ERROR(-20022, 'INVALID_MODE: FOPEN中的open_mode参数无效。');
-- WHEN utl_file.invalid_filehandle THEN
-- RAISE_APPLICATION_ERROR(-20022, 'INVALID_FILEHANDLE: 文件句柄无效。');
-- WHEN utl_file.invalid_operation THEN
-- RAISE_APPLICATION_ERROR(-20033, 'INVALID_OPERATION: 文件无法打开或按要求操作。');
WHEN utl_file.read_error THEN
RAISE_APPLICATION_ERROR(-20044, 'READ_ERROR: 期间发生操作系统错误读操作。');
WHEN utl_file.write_error THEN
RAISE_APPLICATION_ERROR(-20055, 'WRITE_ERROR: :操作系统错误写操作。');
WHEN utl_file.internal_error THEN
RAISE_APPLICATION_ERROR(-20066, 'INTERNAL_ERROR: PL/SQL中未指定的错误。');
END DeleteUploadFile;
END UploadFilePackageV2;
|