以后考慮將CONTENT_HEX字段定義為LRAW類型,這樣直接存儲二進制,數據不會膨脹一倍了(也可采用其他方式,請參考 數據共享與傳遞->DATABASE章節)
"Table: ZJZJPDF 表結構設計如下:
"Field name Key Data element Datatype Length
"MANDT X MANDT CLNT 3
"ROW_ORDER X NUMC 10
"CHR_COUNT INT4 10
"CONTENT_HEX LCHR 510 "注:內類型為 C,並非 X
"LCHR類型的字段前必須有一個INT4類型的字段,並且該字段不能是主鍵,該字段的值為后面
"CONTENT_HEX的字符個數,並且需要在插入表時一並進行插入,否則CONTENT_HEX字段的值不能Select出來
DATA: BEGIN OF xtab255 OCCURS 0,
x(255) TYPE x,"一個字節需使用兩個十六進制字符來表示
END OF xtab255.
DATA: ctab255 TYPE STANDARD TABLE OF solisti1 WITH HEADER LINE.
DATA: BEGIN OF pdf_table OCCURS 0,
mandt TYPE zjzjpdf-mandt,
row_order TYPE zjzjpdf-row_order,
chr_count TYPE zjzjpdf-chr_count,
content_hex(510),"實為字符類型
END OF pdf_table.
********==========================================插入
CALL FUNCTION 'GUI_UPLOAD'
EXPORTING
filename = 'c:\1.txt'
filetype = 'BIN'
TABLES
data_tab = xtab255.
*CALL FUNCTION 'GUI_UPLOAD'
* EXPORTING
* filename = 'c:\1.JPG'
* filetype = 'BIN'
* TABLES
* "接收上傳數據時,按收的內表行類型也可以是Char類型內表
* ",盡管是以BIN 模式上傳的,因為該上傳函數內部還是以
* "X類型視圖來維護ctab255內表的
* data_tab = ctab255.
LOOP AT xtab255.
pdf_table-row_order = sy-tabix.
pdf_table-content_hex = xtab255-x.
"chr_count為內容content_hex字段值的長度,一定要設置,否則下次不能Select出來
pdf_table-chr_count = strlen( pdf_table-content_hex ).
APPEND pdf_table .
ENDLOOP.
DELETE FROM zjzjpdf."清空數據庫表中的所有數據
MODIFY zjzjpdf FROM TABLE pdf_table[]."插入到數據庫
********==========================================讀取
CLEAR: pdf_table[].
SELECT * INTO TABLE pdf_table FROM zjzjpdf.
SORT pdf_table BY row_order.
CLEAR:xtab255[].
LOOP AT pdf_table.
"將數據庫表中字面上的HEX字符串轉換為真正的HEX二進制
xtab255-x = pdf_table-content_hex.
APPEND xtab255.
ENDLOOP.
"注意:雖然是原生態下載,但這里生成的文件在字節數上會多於源文本,並且字節數是255的整數倍,因為在上傳的過程中使用的是xtab255類型的內表,當最后一行不滿255個字節時,也會在后面補上直到255個字節,但補的都是00這樣的字節,所以文件大小還是有區別的,但經過測試pdf與mp3在碼流后面補00字節好像沒有什么影響唯獨是文件大小變大了。但如果是TXT文件,打開后發現多了很多空格(按理來說也是什么也沒有,因為空格的ASCII碼為32,但后面補的是00字節)
CALL FUNCTION 'GUI_DOWNLOAD'
EXPORTING
filename = 'c:\2.txt'
filetype = 'BIN'
TABLES
data_tab = xtab255.
*************************************************************************************
如果需要將PDF以郵件的形式發送出去時,上面的 xtab255 內表接口就已適合於使用cl_document_bcs類的add_attachment方法來發送郵件的i_att_content_hex內表參數接口;但如果使用SO_DOCUMENT_SEND_API1函數的方式來發送郵件時,並使用CONTENTS_BIN過時(可以使用新參參數CONTENTS_HEX內表接口時不需轉換為下面的ctab255內表接口,也可以直接使用上面的xtab255內表接口)的內表參數接口傳遞PDF文件內容時,需要使用下面方式經過轉換后的內表ctab255,即需要將上面的 xtab255 內表中每兩行轉換為 ctab255(行類型為 Char255)內表中的一行(因為一個X類型為一個字節,但在Unicode中一個C可存兩個字節的內容,所以需二行轉換一行操作)
*************************************************************************************
FIELD-SYMBOLS: <x> TYPE x.
DATA: c_tmp1(510) TYPE c.
DATA: c_tmp2(510) TYPE c.
DATA: c_total(1020) TYPE c.
DATA: tabix TYPE i,mod TYPE i.
CLEAR: ctab255[].
LOOP AT xtab255.
tabix = sy-tabix.
mod = tabix MOD 2.
IF mod = 1.
CLEAR: ctab255.
"原來是准備使用字段符號<c>(FIELD-SYMBOLS <c> type c) 指向xtab255-x使用 assign xtab255-x to <c>,但該語句使用時有限制:xtab255-x的類型的長度(所定義的字節數)一定要是4的倍數,否則編譯出錯,所以換成了現在這樣,思路:將賦值雙方中不是X類型的需要以X類型視圖來操作,這樣X類型與X類型賦值時不會發生數據的丟失或者是類型的轉換,而不是將原本為X類型的一方以C或者其類型視圖來看待,這樣在非X類型間的賦值可能會導致數據丟失或發生類型轉換
ASSIGN COMPONENT 'LINE' OF STRUCTURE ctab255 TO <x> CASTING.
c_tmp1 = xtab255-x.
ELSE.
c_tmp2 = xtab255-x.
CONCATENATE c_tmp1 c_tmp2 INTO c_total .
<x> = c_total. "因為4個字面上的十六進制字符才能表示一個字符C,所以從c_total以十六進制方式賦值給ctab255 時,縮短了3/4
APPEND ctab255.
CLEAR: c_tmp1.
ENDIF.
ENDLOOP.
"可能是奇數后,所以需要判斷一下,將最后一行也要附加上去
IF c_tmp1 IS NOT INITIAL.
<x> = c_tmp1.
APPEND ctab255.
ENDIF.
FORM send_email.
DATA: BEGIN OF addr_email OCCURS 0,
smtp_addr(241),
END OF addr_email.
DATA: i_receivers LIKE somlreci1 OCCURS 0 WITH HEADER LINE,
i_message LIKE solisti1 OCCURS 0 WITH HEADER LINE.
DATA: l_subject TYPE so_obj_des,
l_filename TYPE string.
SELECT smtp_addr FROM zmm_invtr_email INTO TABLE addr_email.
CHECK addr_email[] IS NOT INITIAL.
LOOP AT addr_email.
CLEAR:i_receivers.
i_receivers-receiver = addr_email-smtp_addr.
i_receivers-rec_type = 'U'.
i_receivers-com_type = 'INT'.
* i_receivers-copy = 'X'."CC
* i_receivers-blind_copy = 'X'."BCC
i_receivers-express = 'X'."TO
APPEND i_receivers.
ENDLOOP.
l_subject = `hi,baby`."郵件標題
l_filename = 'attach.txt'."附件文件名
i_message-line = `郵件的內容`.
APPEND i_message.
DATA: t_atthead TYPE STANDARD TABLE OF string,
return TYPE bapiret1.
PERFORM send_email_with_att_xls TABLES i_receivers
i_message
t_atthead
<stat_tab>
USING l_subject
sy-uname
l_filename
return.
* MESSAGE return-message TYPE 'S' DISPLAY LIKE return-type.
ENDFORM. "export_xls
*&---------------------------------------------------------------------*
*& Form send_email_with_att_xls
*&---------------------------------------------------------------------*
* 帶XLS附件的郵件發送
*----------------------------------------------------------------------*
* -->T_RECEIVERS 郵件接收者
* -->T_MESSAGE 郵件內容
* -->T_ATTHEAD XLS附件中標題(XLS首行內容)
* -->T_ATTTAB 附件內容
* -->IM_SUBJECT 郵件標題
* -->IM_UNAME 郵件發送者
* -->IM_FILENAME 附件名稱
* -->RETURN 返回信息
*----------------------------------------------------------------------*
FORM send_email_with_att_xls TABLES t_receivers STRUCTURE somlreci1
t_message STRUCTURE solisti1
t_atthead
t_atttab
USING im_subject TYPE so_obj_des
im_uname TYPE uname
im_filename TYPE string
return TYPE bapiret1.
CONSTANTS: c_tab TYPE c VALUE cl_abap_char_utilities=>horizontal_tab,
"回車換行,實質上對應 Xstring: 000D000A
c_crlf(2) TYPE c VALUE cl_abap_char_utilities=>cr_lf.
DATA: xstr TYPE xstring,
it_binary_attach TYPE solix_tab.
************************將內表所有的內容存儲到一個字符串中
DATA: lc_descr_ref TYPE REF TO cl_abap_structdescr,
lv_value TYPE char128,
lv_temp TYPE string,
lv_mid TYPE string.
FIELD-SYMBOLS: <fs_table> TYPE ANY.
FIELD-SYMBOLS: <intable_wa> TYPE abap_compdescr.
CLEAR lv_temp.
"將頭內表拼接成一個字符串
IF t_atthead[] IS NOT INITIAL.
LOOP AT t_atthead.
IF sy-tabix = 1.
lv_temp = t_atthead.
CONTINUE.
ENDIF.
CONCATENATE lv_temp t_atthead
INTO lv_temp SEPARATED BY c_tab.
ENDLOOP.
CONCATENATE lv_temp c_crlf INTO lv_mid.
ENDIF.
"將主體內表拼接成一個字符串
LOOP AT t_atttab.
lc_descr_ref ?= cl_abap_typedescr=>describe_by_data( t_atttab ).
LOOP AT lc_descr_ref->components ASSIGNING <intable_wa>.
ASSIGN COMPONENT sy-tabix OF STRUCTURE t_atttab TO <fs_table>.
"如果是數字類型時
IF <intable_wa>-type_kind = 'P' OR <intable_wa>-type_kind = 'F'
OR <intable_wa>-type_kind = 'I' OR <intable_wa>-type_kind = 'b'
OR <intable_wa>-type_kind = 's'.
IF <fs_table> = 0.
CLEAR lv_value.
ELSE.
WRITE <fs_table> TO lv_value.
CONDENSE lv_value NO-GAPS.
IF <fs_table> < 0."將負號提前
CALL FUNCTION 'CLOI_PUT_SIGN_IN_FRONT'
CHANGING
value = lv_value.
CONDENSE lv_value NO-GAPS.
ENDIF.
ENDIF.
ELSE.
lv_value = <fs_table>.
CONDENSE lv_value.
ENDIF.
IF sy-tabix = 1.
lv_temp = lv_value.
CONTINUE.
ENDIF.
CONCATENATE lv_temp lv_value
INTO lv_temp SEPARATED BY c_tab.
ENDLOOP.
CONCATENATE lv_mid lv_temp c_crlf INTO lv_mid.
ENDLOOP.
************************將字符進行編碼轉換,轉換為二進制字節碼流
DATA: l_codepage(4) TYPE n .
DATA: l_encoding(20).
"將外部字符集名轉換為內部編碼
CALL FUNCTION 'SCP_CODEPAGE_BY_EXTERNAL_NAME'
EXPORTING
external_name = 'UTF-8'
IMPORTING
sap_codepage = l_codepage.
l_encoding = l_codepage.
DATA: convout TYPE REF TO cl_abap_conv_out_ce.
"創建編碼對象
convout = cl_abap_conv_out_ce=>create( encoding = l_encoding ).
convout->write( data = lv_mid )."編碼
xstr = convout->get_buffer( )."獲取碼流
************************接口轉換:將碼流按使用的參數接口要求進行重組轉換
"將 xstring 的字符串存儲到行結構為 X 類型的內表中,以適合於郵件發
"送接口。該函數並不是將 xstring 字符轉換為 二進制(因為xstring本身就
"是原生態,從函數名上看容易誤導)。
CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
EXPORTING
buffer = xstr
TABLES
binary_tab = it_binary_attach.
*另外,也可以將行結構為 X 類型的內表中所有HEX內容拼接成一個Xstring並存儲在l_xstr變量中,也不要被函*數名給迷糊了:並不是將二進制什么的轉換為Xstring類型了,而只不過是將將內表結構轉換為單一的字符串了
*data: l_xstr type xstring.
* clear l_xstr.
* call function 'SCMS_BINARY_TO_XSTRING'
* exporting
* input_length = l_len
* importing
* buffer = l_xstr
* tables
* binary_tab = it_binary_attach.
*-----------------------------------------------------------------------
* Send Email
*-----------------------------------------------------------------------
DATA: lv_title TYPE so_obj_des, " Email Title
lv_email TYPE adsmtp-smtp_addr, " Receiver
lv_attitle TYPE char50. " Attachment Title
DATA: send_request TYPE REF TO cl_bcs,
document TYPE REF TO cl_document_bcs,
conlengths TYPE so_obj_len,
html TYPE TABLE OF w3html,
recipient TYPE REF TO if_recipient_bcs,
sent_to_all TYPE os_boolean,
bcs_exception TYPE REF TO cx_bcs,
bcs_message TYPE string.
DATA: sender TYPE REF TO cl_sapuser_bcs.
TRY.
* 創建發送請求
CLEAR send_request.
send_request = cl_bcs=>create_persistent( ).
CLEAR: lv_title.
lv_title = im_subject.
* 創建並設置郵件文檔
CLEAR html.
REFRESH html.
html = t_message[].
CLEAR document .
document = cl_document_bcs=>create_document(
i_type = 'RAW'
i_text = html
i_length = conlengths
i_subject = lv_title ).
CALL METHOD send_request->set_document( document ).
****************這里也可以從數據庫表中讀取碼流
* DATA: BEGIN OF xtab255 OCCURS 0,
* x(255) TYPE x,
* END OF xtab255.
* FIELD-SYMBOLS: <cc> TYPE c.
*
* DATA: ctab255 TYPE STANDARD TABLE OF solisti1 WITH HEADER LINE.
*
* DATA: BEGIN OF pdf_table OCCURS 0,
* mandt TYPE zjzjpdf-mandt,
* row_order TYPE zjzjpdf-row_order,
* chr_count TYPE zjzjpdf-chr_count,
* content_hex(510),
* END OF pdf_table.
*
* CLEAR: pdf_table[].
* SELECT * INTO TABLE pdf_table FROM zjzjpdf.
* SORT pdf_table BY row_order.
*
* CLEAR: xtab255[].
* LOOP AT pdf_table.
* "將字面上的HEX轉換為真正的HEX
* xtab255-x = pdf_table-content_hex.
* APPEND xtab255.
* ENDLOOP.
****************************
* 添加附件:如果有多個,則需要調用該方法多次
lv_attitle = im_filename.
CALL METHOD document->add_attachment
EXPORTING
* i_attachment_type = 'BIN'"在郵件中點擊附件會彈出文件保存對話框。其他類型請參考SAPFSSOA程序include文件RSSOCONS
* i_attachment_type = 'PDF'
* i_attachment_type = 'TXT'
i_attachment_type = 'XLS'"文件類型,在郵件中就可以打開文件,不會彈出保存對話框
i_attachment_subject = lv_attitle
i_att_content_hex = it_binary_attach.
* i_att_content_hex = xtab255[].
* 設置發送者
sender = cl_sapuser_bcs=>create( im_uname ).
CALL METHOD send_request->set_sender
EXPORTING
i_sender = sender.
* 設置接收者
CLEAR recipient.
LOOP AT t_receivers.
CLEAR lv_email.
lv_email = t_receivers-receiver.
recipient =
cl_cam_address_bcs=>create_internet_address( lv_email ).
CALL METHOD send_request->add_recipient
EXPORTING
i_recipient = recipient
i_express = t_receivers-express
i_copy = t_receivers-copy
i_blind_copy = t_receivers-blind_copy.
ENDLOOP.
* E-mail
CALL METHOD send_request->set_status_attributes
EXPORTING
i_requested_status = 'E'
i_status_mail = 'E'.
CALL METHOD send_request->set_send_immediately( 'X' ).
* 發送郵件
CALL METHOD send_request->send(
EXPORTING
i_with_error_screen = 'X'
RECEIVING
result = sent_to_all ).
COMMIT WORK AND WAIT.
IF sent_to_all = 'X'.
return-message = 'E-mail send successfully'.
return-type = 'S'.
ELSE.
return-message = 'E-mail send unsuccessfully'.
return-type = 'E'.
ENDIF.
CATCH cx_bcs INTO bcs_exception.
bcs_message = bcs_exception->get_text( ).
return-message = bcs_message.
return-type = 'E'.
EXIT.
ENDTRY.
ENDFORM.