1. 程式人生 > >檔案上傳原理實現

檔案上傳原理實現

檔案上傳原理實現

2010年09月07日 18:22:00 一步一個腳印 閱讀數:23920 標籤: stringnullconstructorbyteclassiterator 更多

個人分類: 3001_基礎綜合知識2001_程式語言20011_Java

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/ybygjy/article/details/5869158

檔案上傳原理實現

客戶端瀏覽器是怎樣上傳資料的呢?伺服器端如何接收上傳的檔案資料?

級別: 初級

王延成 (王延成

), 作者/編者, 

2004 年 9 月 01 日

文章主要描述http表單上傳二進位制資料流規範的簡單實現

(一)關於Form表單上傳檔案規範

  總結個人在對新技術、新事物的學習和解決問題的過程,深刻體會到多理解掌握技術基礎理論知識再加上相應的實踐,的確能幫助我們在解決某些問題的時候起到事半功倍的效果。

以前上傳檔案類似的功能都是採用第三方元件來做的,真的是基於介面程式設計了。不出問題還好,真要是出現問題解決起來太不舒服了,往往屬於那種拆了西牆補東牆的策略。最近,在做檔案上傳時學習了一些 關於html>form上傳資料的格式規範,依據人家定義的規範做了一些簡單的工作。。。算是實現了個小輪子吧。


(二)實現

1、規則

1.1 上傳資料塊的分割規則

基於html form表單上傳的資料都是以類似-----------------------------7da3c8e180752{0x130x10}這樣的分割符來標記一塊資料的起止,可不要忘記後面的兩個換行符。關於換行符有三種,如下:

作業系統 換行符描述 原始標記 ascii碼 十六進位制
Window Window的換行符是兩個 //r//n 1310 0x0d0x0a
Unix Unix的換行符是一個 //n 10 0x0a
Mac OS Mac OS的換行符是一個 //r 13 0x0d
這塊沒有對Unix、MacOS上做測試,只在Window上測試了換行是兩個(0x0d0x0a)

1.2 注意在後臺從request中取得分割串少兩個--,在看下面的原始資料你會發現流的最後是以--結束的。1.3 上傳的原始資料串,本來中文字元是亂碼的。為了清晰一些使用字符集UTF-8轉了下碼。

 [xhtml] view plain copy
  1. -----------------------------7da3c8e180752  
  2. Content-Disposition: form-data; name="fileData1"; filename="C:/abcdef.log"  
  3. Content-Type: application/octet-stream  
  4.   
  5. HelloWorld  
  6. HelloWorld  
  7.   
  8. -----------------------------7da3c8e180752  
  9. Content-Disposition: form-data; name="fileData2"; filename="C:/deleteThumb.bat"  
  10. Content-Type: application/octet-stream  
  11.   
  12. FOR %%a IN ( C: D: E: F: ) DO DEL /f/s/q/a %%a/Thumbs.db  
  13. -----------------------------7da3c8e180752  
  14. Content-Disposition: form-data; name="textAreaContent"  
  15.   
  16. HelloWorld  
  17. -----------------------------7da3c8e180752  
  18. Content-Disposition: form-data; name="id"  
  19.   
  20. 檔案編碼  
  21. -----------------------------7da3c8e180752  
  22. Content-Disposition: form-data; name="name"  
  23.   
  24. 檔名稱  
  25. -----------------------------7da3c8e180752--  

1.4 小結

基於1.3小節可以非常容易總結歸納出html-->form元素內容。有兩個檔案型別元素,三個text元素(其中一個元素是textarea)

2、操作順序流程描述


回頁首

3、實現程式碼

需要明確注意的一個問題是關於request.getInputStream();獲取請求體資料流不可用的問題,見示例程式碼:

 

[java] view plain copy

  1. /*我是這麼認為的在獲取流之前,已經通過第三方應用伺服器相關對ServletRequest介面實現解析過流了,所以我們再次取請求流內容時會有問題。。在參與.NET裝置與JavaWeb互動時也遇到過此型別的問題。*/  
  2. /*這就要求我們如果是自己解析request流內容資料,在解析之前不可以呼叫getParameter(String paramName)相關的需要用到解析流的行為方法。*/  
  3. /*以上僅個人理解、個人意見,如有不對請多多指正。*/  
  4. request.getParameter("USER_CODE");  
  5. InputStream ins = request.getInputStream();  
  6. byte[] buff = new byte[1024];  
  7. int count = -1;  
  8. while ((count = ins.read(buff))!=-1) {  
  9.     System.out.println(new String(buff,0, count, "UTF-8"));  
  10. }  

3.1、類圖

3.2、程式碼內容

入口Servlet

[java] view plain copy

  1. package org.ybygjy.web;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.Iterator;  
  5. import java.util.List;  
  6.   
  7. import javax.servlet.ServletException;  
  8. import javax.servlet.http.HttpServlet;  
  9. import javax.servlet.http.HttpServletRequest;  
  10. import javax.servlet.http.HttpServletResponse;  
  11.   
  12. import org.ybygjy.web.comp.FileItem;  
  13. import org.ybygjy.web.comp.FileMgrComp;  
  14. import org.ybygjy.web.utils.WrapperRequest;  
  15.   
  16. /** 
  17.  * 處理基於WebHttp的請求/響應 
  18.  * @author WangYanCheng 
  19.  * @version 2010-1-10 
  20.  */  
  21. public class Servlet extends HttpServlet {  
  22.     /** default serial */  
  23.     private static final long serialVersionUID = 1L;  
  24.   
  25.     /** 
  26.      * {@inheritDoc} 
  27.      */  
  28.     public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,  
  29.         IOException {  
  30.         request.setCharacterEncoding("UTF-8");  
  31.         List<FileItem> fileItemArr = null;  
  32.         String contentType = request.getContentType();  
  33.         if (null != contentType && contentType.startsWith(WrapperRequest.ContentType.FORM_DATA.getType())) {  
  34.             fileItemArr = new FileMgrComp().doAnalyse(WrapperRequest.getInstance(request), response);  
  35.             for (Iterator<FileItem> iterator = fileItemArr.iterator(); iterator.hasNext();) {  
  36.                 System.out.println(iterator.next());  
  37.             }  
  38.         }  
  39.     }  
  40. }  

  

工具類


回頁首

[java] view plain copy

  1. package org.ybygjy.web.utils;  
  2.   
  3. import javax.servlet.http.HttpServletRequest;  
  4.   
  5. /** 
  6.  * RequestUtils 
  7.  * @author WangYanCheng 
  8.  * @version 2010-1-10 
  9.  */  
  10. public class WrapperRequest {  
  11.     /**ContentType*/  
  12.     public enum ContentType {  
  13.         /**MIME型別-二進位制資料標記*/  
  14.         FORM_DATA("multipart/form-data"),  
  15.         /**MIME型別-標準編碼格式標記*/  
  16.         FORM_URLENCODE("application/x-www-form-urlencoded"),  
  17.         /**MIME型別-文字格式標記*/  
  18.         FORM_TEXT("text/plain");  
  19.         /**inner type*/  
  20.         private final String type;  
  21.         /** 
  22.          * Constructor 
  23.          * @param str type 
  24.          */  
  25.         private ContentType(String str) {  
  26.             this.type = str;  
  27.         }  
  28.         /** 
  29.          * getter Type 
  30.          * @return type 
  31.          */  
  32.         public String getType() {  
  33.             return this.type;  
  34.         }  
  35.     }  
  36.     /**ContentType*/  
  37.     private String contentType;  
  38.     /**request*/  
  39.     private HttpServletRequest request = null;  
  40.     /** 
  41.      * Constructor 
  42.      * @param request request 
  43.      */  
  44.     private WrapperRequest(HttpServletRequest request) {  
  45.         this.request = request;  
  46.     }  
  47.     /** 
  48.      * getInstance 
  49.      * @param request request 
  50.      * @return wrapperRequest 
  51.      */  
  52.     public static final WrapperRequest getInstance(HttpServletRequest request) {  
  53.         return new WrapperRequest(request);  
  54.     }  
  55.     /** 
  56.      * get no wrapper Request 
  57.      * @return request request/null 
  58.      */  
  59.     public HttpServletRequest getRequest() {  
  60.         return this.request;  
  61.     }  
  62.     /** 
  63.      * getContentType 
  64.      * @return contentTypeStr/null 
  65.      */  
  66.     public String getContentType() {  
  67.         if (null == this.contentType) {  
  68.             this.contentType = null == this.request ? null : this.request.getContentType();  
  69.         }  
  70.         return this.contentType;  
  71.     }  
  72.     /** 
  73.      * 是否二制資料格式 
  74.      * @return true/false 
  75.      */  
  76.     public boolean isBinaryData() {  
  77.         boolean rtnBool = false;  
  78.         String tmpStr = getContentType();  
  79.         if (tmpStr.contains(ContentType.FORM_DATA.getType())) {  
  80.             rtnBool = true;  
  81.         }  
  82.         return rtnBool;  
  83.     }  
  84.     /** 
  85.      * 取得內容界定符 
  86.      * @return rtnStr/null 
  87.      */  
  88.     public String getBoundary() {  
  89.         String rtnStr = null;  
  90.         String tmpType = getContentType();  
  91.         if (null != tmpType) {  
  92.             rtnStr = tmpType.matches("^[//s//S]*boundary=[//s//S]*$") ? tmpType.split("boundary=")[1] : null;  
  93.         }  
  94.         return "--".concat(rtnStr);  
  95.     }  
  96.     /** 
  97.      * 測試入口 
  98.      * @param args 引數列表 
  99.      */  
  100.     public static void main(String[] args) {  
  101. //        WrapperRequest.ContentType[] cts = WrapperRequest.ContentType.values();  
  102. //        for (WrapperRequest.ContentType ct : cts) {  
  103. //            System.out.println(ct.getType());  
  104. //        }  
  105. //        System.out.println(WrapperRequest.getInstance(null).getBoundary());  
  106.         /*Matcher matcher = Pattern.compile("(//s)+").matcher("分/n/r割符"); 
  107.         while (matcher.find()) { 
  108.             int count = matcher.groupCount(); 
  109.             for (int i = 0; i < count; i++) { 
  110.                 byte[] tmpByte = matcher.group(i).getBytes(); 
  111.                 for (int tmpI : tmpByte) { 
  112.                     System.out.print(tmpI); 
  113.                 } 
  114.             } 
  115.         }*/  
  116.         WrapperRequest wpInst = WrapperRequest.getInstance(null);  
  117.         wpInst.getBoundary();  
  118.     }  
  119. }  

  基礎實現[java] view plain copy

  1. package org.ybygjy.web.comp;  
  2.   
  3. import java.io.BufferedOutputStream;  
  4. import java.io.File;  
  5. import java.io.FileOutputStream;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.io.OutputStream;  
  9.   
  10. import org.ybygjy.web.utils.FileUtils;  
  11.   
  12. /** 
  13.  * 負責檔案的儲存解析 
  14.  * @author WangYanCheng 
  15.  * @version 2010-08-31 
  16.  */  
  17. public class FileItem {  
  18.     /** 原始檔路徑 */  
  19.     private String srcFilePath;  
  20.     /** 原始檔全名稱 */  
  21.     private String srcFileFullName;  
  22.     /** 原始檔名稱 */  
  23.     private String srcFileName;  
  24.     /** 檔案轉儲路徑 */  
  25.     private String filePath;  
  26.     /** 檔名稱 */  
  27.     private String fileName;  
  28.     /** 檔案全名稱 */  
  29.     private String fileFullName;  
  30.     /** 上傳檔案引數名稱 */  
  31.     private String paramName;  
  32.     /** MIME Type */  
  33.     private String mimeType;  
  34.     /** 分割串 */  
  35.     private String boundaryStr;  
  36.   
  37.     /** 
  38.      * Constructor 
  39.      * @param paramStr 引數名稱 
  40.      * @param fileStr 原始檔地址串 
  41.      * @param mimeType MIMEType 
  42.      * @param boundaryStr 分割約束 
  43.      */  
  44.     public FileItem(String paramStr, String fileStr, String mimeType, String boundaryStr) {  
  45.         String[] tmpStrArr = paramStr.split("=");  
  46.         this.setParamName(tmpStrArr[1].substring(1, tmpStrArr[1].length() - 1));  
  47.         tmpStrArr = fileStr.split("=");  
  48.         this.setSrcFilePath(tmpStrArr[1].substring(1, tmpStrArr[1].length() - 1));  
  49.         this.setMIME(mimeType);  
  50.         this.setBoundaryStr(boundaryStr);  
  51.     }  
  52.   
  53.     /** 
  54.      * setFilePath 
  55.      * @param filePath filePath 
  56.      */  
  57.     public void setSrcFilePath(String filePath) {  
  58.         this.srcFilePath = filePath;  
  59.         if (this.srcFilePath != null && filePath.length() > 0) {  
  60.             this.srcFileFullName = new File(this.srcFilePath).getName();  
  61.             this.srcFileName = this.srcFileFullName.substring(0, this.srcFileFullName.indexOf('.'));  
  62.         }  
  63.     }  
  64.   
  65.     /** 
  66.      * setMIME 
  67.      * @param mimeType mimeType 
  68.      */  
  69.     public void setMIME(String mimeType) {  
  70.         this.mimeType = mimeType;  
  71.     }  
  72.   
  73.     /** 
  74.      * getMIME 
  75.      * @return mimeType mimeType 
  76.      */  
  77.     public String getMIME() {  
  78.         return this.mimeType;  
  79.     }  
  80.   
  81.     /** 
  82.      * setBoundary 
  83.      * @param boundaryStr the boundaryStr to set 
  84.      */  
  85.     public void setBoundaryStr(String boundaryStr) {  
  86.         this.boundaryStr = boundaryStr;  
  87.     }  
  88.   
  89.     /** 
  90.      * setParamName 
  91.      * @param paramName paramName 
  92.      */  
  93.     public void setParamName(String paramName) {  
  94.         this.paramName = paramName;  
  95.     }  
  96.   
  97.     /** 
  98.      * getParamName 
  99.      * @return paramName 
  100.      */  
  101.     public String getParamName() {  
  102.         return this.paramName;  
  103.     }  
  104.   
  105.     /** 
  106.      * 源上傳檔案全名稱 
  107.      * @return the srcFileName 
  108.      */  
  109.     public String getSrcFileFullName() {  
  110.         return srcFileFullName == null ? null : srcFileFullName.length() == 0 ? null : this.srcFileFullName;  
  111.     }  
  112.   
  113.     /** 
  114.      * 源上傳檔名稱 
  115.      * @return the srcFileName 
  116.      */  
  117.     public String getSrcFileName() {  
  118.         return srcFileName;  
  119.     }  
  120.   
  121.     /** 
  122.      * 檔案儲存路徑 
  123.      * @return the filePath 
  124.      */  
  125.     public String getFilePath() {  
  126.         return filePath;  
  127.     }  
  128.   
  129.     /** 
  130.      * 取檔名稱 
  131.      * @return the fileName 
  132.      */  
  133.     public String getFileName() {  
  134.         return fileName;  
  135.     }  
  136.   
  137.     /** 
  138.      * 取檔案全名稱 
  139.      * @return the fileFullName 
  140.      */  
  141.     public String getFileFullName() {  
  142.         return fileFullName;  
  143.     }  
  144.   
  145.     /** 
  146.      * 轉儲檔案 
  147.      * @param ins ins 
  148.      * @throws IOException IOException 
  149.      */  
  150.     public void doStoreFile(InputStream ins) throws IOException {  
  151.         String id = String.valueOf(System.currentTimeMillis());  
  152.         File tmpFile = new File(FileUtils.getTmpFilePath(), id);  
  153.         this.filePath = tmpFile.getPath();  
  154.         this.fileFullName = tmpFile.getName();  
  155.         this.fileName = id;  
  156.         BufferedOutputStream bos = null;  
  157.         try {  
  158.             bos = new BufferedOutputStream(new FileOutputStream(tmpFile));  
  159.             this.doStoreFile(ins, bos);  
  160.         } catch (IOException ioe) {  
  161.             throw ioe;  
  162.         } finally {  
  163.             try {  
  164.                 bos.close();  
  165.             } catch (IOException ioe) {  
  166.                 ioe.printStackTrace();  
  167.             }  
  168.         }  
  169.     }  
  170.   
  171.     /** 
  172.      * 儲存檔案 
  173.      * @param ins ins 
  174.      * @param bos bos 
  175.      * @throws IOException IOException 
  176.      */  
  177.     private void doStoreFile(InputStream ins, OutputStream bos) throws IOException {  
  178.         byte[] byteArr = new byte[this.boundaryStr.getBytes().length];  
  179.         try {  
  180.             int tmpI = -1;  
  181.             int tmpL = -1;  
  182.             ins.skip(2);  
  183.             while (((tmpI = ins.read()) != -1)) {  
  184.                 if (13 == tmpI) {  
  185.                     tmpL = ins.read();  
  186.                     if (10 == tmpL && isBoundary(ins, byteArr)) {  
  187.                         break;  
  188.                     } else {  
  189.                         bos.write(tmpI);  
  190.                         bos.write(tmpL);  
  191.                         if (10 == tmpL) {  
  192.                             bos.write(byteArr);  
  193.                         }  
  194.                         continue;  
  195.                     }  
  196.                 }  
  197.                 bos.write(tmpI);  
  198.             }  
  199.             bos.flush();  
  200.         } catch (IOException ioe) {  
  201.             throw ioe;  
  202.         }  
  203.     }  
  204.   
  205.     /** 
  206.      * 檢驗是否邊界 
  207.      * @param ins ins 
  208.      * @param byteArr byteArr 
  209.      * @return true/false 
  210.      * @throws IOException IOException 
  211.      */  
  212.     private boolean isBoundary(InputStream ins, byte[] byteArr) throws IOException {  
  213.         if (null == this.boundaryStr) {  
  214.             return false;  
  215.         }  
  216.         boolean rtnFlag = false;  
  217.         int count = ins.read(byteArr);  
  218.         if (count != -1) {  
  219.             String str = new String(byteArr, 0, count);  
  220.             if (this.boundaryStr.equals(str)) {  
  221.                 rtnFlag = true;  
  222.             }  
  223.             byteArr = str.getBytes();  
  224.         }  
  225.         return rtnFlag;  
  226.     }  
  227.   
  228.     @Override  
  229.     public String toString() {  
  230.         StringBuilder builder = new StringBuilder();  
  231.         builder.append("FileItem [boundaryStr=");  
  232.         builder.append(boundaryStr);  
  233.         builder.append(", fileFullName=");  
  234.         builder.append(fileFullName);  
  235.         builder.append(", fileName=");  
  236.         builder.append(fileName);  
  237.         builder.append(", filePath=");  
  238.         builder.append(filePath);  
  239.         builder.append(", mimeType=");  
  240.         builder.append(mimeType);  
  241.         builder.append(", paramName=");  
  242.         builder.append(paramName);  
  243.         builder.append(", srcFileName=");  
  244.         builder.append(srcFileFullName);  
  245.         builder.append(", srcFilePath=");  
  246.         builder.append(srcFilePath);  
  247.         builder.append("]");  
  248.         return builder.toString();  
  249.     }  
  250. }  

  


回頁首

[java] view plain copy

  1. package org.ybygjy.web.comp;  
  2.   
  3. import java.io.BufferedInputStream;  
  4. import java.io.ByteArrayOutputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7. import java.io.UnsupportedEncodingException;  
  8. import java.util.ArrayList;  
  9. import java.util.HashMap;  
  10. import java.util.List;  
  11. import java.util.Map;  
  12.   
  13. import javax.servlet.http.HttpServletRequest;  
  14. import javax.servlet.http.HttpServletResponse;  
  15.   
  16. import org.ybygjy.web.utils.WrapperRequest;  
  17.   
  18. /** 
  19.  * 負責對檔案實體進行的操作 
  20.  * @author WangYanCheng 
  21.  * @version 2010-8-27 
  22.  */  
  23. public class FileMgrComp {  
  24.   
  25.     /** serialNumber */  
  26.     private static final long serialVersionUID = 5563862601527965192L;  
  27.     /** boundaryStr */  
  28.     private String boundaryStr;  
  29.     /** ifcArray */  
  30.     private List<FileItem> ifcArray;  
  31.   
  32.     /** 
  33.      * Constructor 
  34.      */  
  35.     public FileMgrComp() {  
  36.         ifcArray = new ArrayList<FileItem>();  
  37.     }  
  38.   
  39.     /** 
  40.      * doService 
  41.      * @param wrRequest wrRequest 
  42.      * @param response response 
  43.      * @return rtnList rtnList/null 
  44.      * @throws IOException IOException 
  45.      */  
  46.     public List<FileItem> doAnalyse(WrapperRequest wrRequest, HttpServletResponse response) throws IOException {  
  47. doInnerTest(wrRequest.getRequest());  
  48.         List<FileItem> fileArr = null;  
  49.         if (wrRequest.isBinaryData()) {  
  50.             this.boundaryStr = wrRequest.getBoundary();  
  51.             if (null != boundaryStr) {  
  52.                 fileArr = doAnalyseBinaryData(wrRequest);  
  53.             }  
  54.         }  
  55.         return fileArr;  
  56.     }  
  57.   
  58.     /** 
  59.      * 分析儲存二進位制資料 
  60.      * @param wrRequest wrRequest 
  61.      * @return fileItemArr fileItemArr 
  62.      */  
  63.     private List<FileItem> doAnalyseBinaryData(WrapperRequest wrRequest) {  
  64.         BufferedInputStream bins = null;  
  65.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  66.         try {  
  67.             bins = new BufferedInputStream(wrRequest.getRequest().getInputStream());  
  68.             int tmpI = -1;  
  69.             int tmpL = -1;  
  70.             while ((tmpI = bins.read()) != -1) {  
  71.                 if (tmpI == 13) {  
  72.                     tmpL = (bins.read());  
  73.                     if (tmpL == 10) {  
  74.                         if (baos.size() == 0) {  
  75.                             continue;  
  76.                         }  
  77.                         FileItem fi = analyseFileInput(baos, bins);  
  78.                         if (fi != null) {  
  79.                             ifcArray.add(fi);  
  80.                         }  
  81.                         baos.reset();  
  82.                         continue;  
  83.                     }  
  84.                     baos.write(tmpI);  
  85.                     baos.write(tmpL);  
  86.                 }  
  87.                 baos.write(tmpI);  
  88.             }  
  89.         } catch (IOException ioe) {  
  90.             ioe.printStackTrace();  
  91.         } finally {  
  92.             if (null != bins) {  
  93.                 try {  
  94.                     baos.close();  
  95.                     bins.close();  
  96.                 } catch (IOException e) {  
  97.                     e.printStackTrace();  
  98.                 }  
  99.             }  
  100.         }  
  101.         return this.getIfcArray();  
  102.     }  
  103.   
  104.     /** 
  105.      * 解析驗證上傳內容是否檔案型別 
  106.      * @param os outStream 
  107.      * @param ins insStream 
  108.      * @return ifcInst ifcInst/null 
  109.      */  
  110.     private FileItem analyseFileInput(ByteArrayOutputStream os, InputStream ins) {  
  111.         String tmpStr = null;  
  112.         try {  
  113.             tmpStr = os.toString("UTF-8");  
  114.         } catch (UnsupportedEncodingException e1) {  
  115.             e1.printStackTrace();  
  116.         }  
  117.         FileItem ifcIns = null;  
  118.         if (tmpStr.indexOf("filename") != -1) {  
  119.             String[] tmpStrArr = tmpStr.split(";");  
  120.             if (tmpStrArr.length > 2) {  
  121.                 // 取MIME檔案型別  
  122.                 ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  123.                 try {  
  124.                     doRead(ins, baos);  
  125.                     tmpStr = baos.toString();  
  126.                     if (tmpStr.startsWith("Content-Type:")) {  
  127.                         ifcIns = new FileItem(tmpStrArr[1].trim(), tmpStrArr[2].trim(),  
  128.                             tmpStr.split(":")[1].trim(), this.boundaryStr);  
  129.                         if (ifcIns.getSrcFileFullName() != null) {  
  130.                             ifcIns.doStoreFile(ins);  
  131.                         }  
  132.                     }  
  133.                 } catch (IOException e) {  
  134.                     e.printStackTrace();  
  135.                 } finally {  
  136.                     try {  
  137.                         baos.close();  
  138.                     } catch (IOException ioe) {  
  139.                         ioe.printStackTrace();  
  140.                     }  
  141.                 }  
  142.             }  
  143.         }  
  144.         return ifcIns;  
  145.     }  
  146.   
  147.     /** 
  148.      * doRead 
  149.