频繁数据集挖掘的一种实现方式

来源:互联网 发布:下载天际通软件 编辑:程序博客网 时间:2024/06/01 08:15

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.swing.text.html.HTMLDocument.Iterator;

import com.sun.org.apache.xalan.internal.xsltc.runtime.Hashtable;

/**
 * 本程序用于频繁集的挖掘 首先用List<List<String>>类型的record将矩阵形式的数据读入内存;
 *
 * 程序先求出k-1备选集,由备选集和数据库记录record求得满足支持度的k-1级集合,在满足支持度集合中求出满足自信度的集合,
 * 若满足置信度的集合为空,程序停止; 否则输出满足自信度的集合,以及对应的支持度和自信度,并由满足支持度的k-1级集合求出k级备选集,进入下一轮循环;
 * 直至程序结束,输出全部频繁级
 */

public class CopyOfApriorilesNew {

    public static SimpleDateFormat DATE_TEMPLATE = new SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");
    public static List<List<String>> TIME_LABEL_LIST = new ArrayList<List<String>>();// 生成事务的日志事件
    public static List<List<String>> transactions = new ArrayList<List<String>>(); // 事务序列
    public static int windowSize = 30; // 窗口大小
    public static int stepSize = 10; // 移动步长
    //public static List<List<List<String>>> allITtemSets = new ArrayList<List<List<String>>>(); // 存放所有的候选项集(不包含候选1项集)
    //public static List<List<List<String>>> allFItemSets = new ArrayList<List<List<String>>>(); // 存放所有的频繁项集(不包含频繁1项集)
    //public static List<List<Integer>>  allCandidateSupporCount = new ArrayList<List<Integer>>(); // 存放所有候选项集的事件数
                                                                                                
    public static List<List<Integer>> supporCount = new ArrayList<List<Integer>>(); // 存放每个频繁项集的事件数
    public static List<List<List<String>>> eventRules = new ArrayList<List<List<String>>>(); // 存放所有的事件规则
    static boolean endTag = false; // 循环是否进行的标志
    final static int MIN_SUPPORT = 10;   // 支持度阈值(事件数)
    final static double MIN_CONF = -1;   // 置信度阈值
    //public static List<List<String>> allFItemSetConfidence = new ArrayList<List<String>>(); // 存放所有频繁项的置信度
    public static List<List<String>> satisfiedConfidence = new ArrayList<List<String>>(); // 存放表示满足置信度阈值的(事件规则)频繁项的置信度
    public static String exportConfidence = new String();
    //public static int eventCount = 0;

    /**
     * @param args
     * @throws ParseException
     */
    public static void main(String[] args) throws ParseException {
        // TODO Auto-generated method stub
        
        getRecord();      // 获取按时间排序的日志记录
        getTransactions(windowSize, stepSize); // 生成事务

        List<String> oneFItemset = findFirstFrequenItemset();    // 获取一项频繁项集,用哈希表存储
        List<List<String>> cItemset = findSencondCandidate(oneFItemset); // 获取二项候选项集
        List<List<String>> fItemset = getSupportedItemset(cItemset); // 获取二项候选项集cItemset满足支持的集合
        getSecondConfidencedItemset(fItemset, oneFItemset); // 获取二项事件规则
        while (endTag != true) { // 只要能继续挖掘
            List<List<String>> ckItemset = getNextCandidate(fItemset); // 获取第下一次的候选集
            List<List<String>> fkItemset = getSupportedItemset(ckItemset); // 获取候选集cItemset满足支持的集合
            getConfidencedItemset(fkItemset, fItemset); // 获取频繁项集满足置信度的集合
            fItemset=fkItemset;
        }
        
        print();  
    
        System.out.print("The program is finished!");
    }
    
//    private static void test(){
//        //String str="1a 2a 3a 4a 5a 1a 1a 1a 2a 3a 4a 1a 1a 5a 1a 1a 1a 2a 4a 5a 1a 1a 1a 1a 1a 1a";
//        //String str="1a 2a 3a 4a";
//        String str="1a 2a";
//        String [] a=str.split(" ");
//        List<String> se=new  ArrayList<String>();
//        se=Arrays.asList(a);
//        List<String> Item=new  ArrayList<String>();
//        Item.add("1a");
//        Item.add("2a");
//        Item.add("3a");
//        Item.add("4a");
//        Item.add("5a");
//        int in=countSupportCount(se,Item);
//        System.out.print(in);
//        
//        
//        
//        
//        
//    }
    /**
     * 读取按时间排序后的日志
     */
    private static void getRecord() {
        
        String TimeSortedLogFile ="/home/wdl/test/alertLog_Sorted.txt";
        try {
            File File = new File(TimeSortedLogFile);
            BufferedReader wReader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(TimeSortedLogFile), "UTF-8"));
            String line = null;
            while ((line = wReader.readLine()) != null) {
                if ("".equals(line.trim())) { // 遇空行,略过继续执行
                    continue;
                }
                List<String> tempList = new ArrayList<String>();
                String[] logArr = line.split("\t");
                tempList.add(logArr[0]);
                tempList.add(logArr[1]);
                TIME_LABEL_LIST.add(tempList);
            }
            wReader.close();
        } catch (IOException e1) {
            e1.printStackTrace();
        }

    }


    /**
     * 获取事务
     * @param windowSize  窗口大小
     * @param stepSize
     * @throws ParseException
     */
    public static void getTransactions(int windowSize, int stepSize)
            throws ParseException {
        System.out.print("进入getTransaction函数");
        List<List<String>> tempTransactions = new ArrayList<List<String>>();
        // List<List<String>> transactions = new ArrayList<List<String>>();//
        // 用来存放事务
        int logMergeListLength = TIME_LABEL_LIST.size(); // 数据集大小
        // 获取合并后的数据集的最早时间
        Date minDate = DATE_TEMPLATE.parse(TIME_LABEL_LIST.get(0).get(0)); // 0存放的是时间
        // 获取合并后的数据集的最晚时间
        Date endDate = DATE_TEMPLATE.parse(TIME_LABEL_LIST.get(
                logMergeListLength - 1).get(0));
        // 设置开始时间
        Calendar cal = Calendar.getInstance();
        cal.setTime(minDate);
        // 设置时间窗口大小
        cal.add(Calendar.MINUTE, windowSize);
        Date maxDate = cal.getTime();
        Date stepDate = cal.getTime();
        int curIndex = 0;// 当前时间
        int stepIndex = 0;// 移动一个步长后所在的时间
        while (minDate.getTime() < endDate.getTime()) {
            // 保存当前时间窗口内的类别数据到set集合中
            List<String> curLogSet = new ArrayList<String>(); // 改成用List存储,存储重复元素
            curIndex = stepIndex; // 日志索引号赋值为上一个步长出的索引号,每次增加一个步长
            cal.setTime(minDate);
            cal.add(Calendar.MINUTE, stepSize);
            stepDate = cal.getTime();
            for (int i = curIndex; i < TIME_LABEL_LIST.size(); i++) {
                Date timeStamp = DATE_TEMPLATE.parse(TIME_LABEL_LIST.get(i)
                        .get(0));
                if (timeStamp.getTime() >= minDate.getTime()
                        && timeStamp.getTime() < maxDate.getTime()) {
                    curLogSet.add(TIME_LABEL_LIST.get(i).get(1));
                } else if (timeStamp.getTime() >= maxDate.getTime()) {
                    break;
                }
                if (timeStamp.getTime() <= stepDate.getTime()) {
                    stepIndex++; // 如果时间在当前步长内,日志索引号加一
                }
            }
            // 窗口最大最小时间下滑一个步长
            cal.setTime(minDate);
            cal.add(Calendar.MINUTE, stepSize);
            minDate = cal.getTime();
            cal.setTime(maxDate);
            cal.add(Calendar.MINUTE, stepSize);
            maxDate = cal.getTime();
            tempTransactions.add(curLogSet);
        }
        for (int i = 0; i < tempTransactions.size(); i++) { // 去除事务中为空的子序列
            if (tempTransactions.get(i).size() != 0) {
                transactions.add(tempTransactions.get(i));
            }
        }

    }

    /**
     * 获取频繁一项集
     * @return
     */
    public static List<String> findFirstFrequenItemset() {
        int count = 1;
        Map<String, Integer> oneCandidateItemSetAndCount = new HashMap<String, Integer>();
        Map<String, Integer> oneFrequentItemSetAndCount = new HashMap<String, Integer>();
        for(List<String>  transactionList:transactions ){                //从各个事务中得到频繁一项集
            count = 1;
            for(String tempStr:transactionList){
                 if(oneCandidateItemSetAndCount.containsKey(tempStr)){
                     count = (int) oneCandidateItemSetAndCount.get(tempStr) + 1;    
                 }
             oneCandidateItemSetAndCount.put( tempStr,count);
             }    
        }
        for (Entry<String, Integer> entry : oneCandidateItemSetAndCount   // 测试,查看频繁一项集是否求解正确
                .entrySet()) {
            System.out.println("输出候选一项集:");
            System.out.println(entry.getKey() + "=" + entry.getValue());
            System.out.println("\r\n");
        }
        for (Entry<String, Integer> entry : oneCandidateItemSetAndCount  // 求频繁一项集
                .entrySet()) {
            if ((int) entry.getValue() > MIN_SUPPORT) {
                oneFrequentItemSetAndCount
                        .put(entry.getKey(), entry.getValue());
            }
        }
        
        List<Integer> tempList = new ArrayList<Integer>();
        for (Entry<String, Integer> entry : oneFrequentItemSetAndCount
                .entrySet()) {
            tempList.add(entry.getValue());
        }
        supporCount.add(tempList);             // 将频繁一项集的事件数存储到supporCount中
        List<String> oneFItemset = new ArrayList<String>();

        for (Entry<String, Integer> entry : oneFrequentItemSetAndCount
                .entrySet()) {
            oneFItemset.add(entry.getKey());  // 将频繁一项集的各项事件存储到oneFItemset中
        }

        return oneFItemset;
    }

    
    /**
     * 获取二项候选集
     * @param oneFItemSet
     * @return
     */
    public static List<List<String>> findSencondCandidate(
            List<String> oneFItemSet) {                     // 生成二项候选项集
        List<List<String>> twoCandidateItemSet = new ArrayList<List<String>>();
        for (int i = 0; i < oneFItemSet.size(); i++) {     // 生成一半二项候选项集
            for (int j = i + 1; j < oneFItemSet.size(); j++) {
                List<String> tempList = new ArrayList<String>();
                tempList.add(oneFItemSet.get(i));
                tempList.add(oneFItemSet.get(j));
                twoCandidateItemSet.add(tempList);
            }
        }
        int halfTwoCandidateItemSize = twoCandidateItemSet.size();  // 二项候选项元素大小的一半
        for (int i = 0; i < halfTwoCandidateItemSize; i++) {       // 获取二项候选项集的另一半
            List<String> tempList = new ArrayList<String>();
            tempList.add(twoCandidateItemSet.get(i).get(1));
            tempList.add(twoCandidateItemSet.get(i).get(0));
            twoCandidateItemSet.add(tempList);
        }
        return twoCandidateItemSet;
    }

    
    /**
     * 获取K项集中所有的频繁项
     * @param cItemset
     * @return
     */
    public static List<List<String>> getSupportedItemset(        // 从K〉=2开始计算事件数
            List<List<String>> cItemset) {
        // TODO Auto-generated method stub
        System.out.print("进入getSupportedItemset");
        boolean end = true;
        int totalCount = 0;
        int count = 0;
        List<List<String>> supportedItemset = new ArrayList<List<String>>();
        List<Integer> tempList = new ArrayList<Integer>();
        for (int i = 0; i < cItemset.size(); i++) {          // 对频繁项集中的每一项扫描整个事务库
            totalCount = 0;
            count = 0;
            for (int j = 0; j < transactions.size(); j++) {
                count = countSupportCount(transactions.get(j), cItemset.get(i));    //统计记录数
                totalCount = totalCount + count;
            }
            if (totalCount > MIN_SUPPORT) {          // count值大于规定阈值,即满足要求
                tempList.add(totalCount);           // 存储频繁项集中频繁项的事件数
                supportedItemset.add(cItemset.get(i));       // supportedItemset存放频繁项集
                end = false;
            }
        }
        supporCount.add(tempList);        // 存储每个频繁项集的事件数
        endTag = end;                    // 挖掘终止与否
        return supportedItemset;
    }

    
    /**
     * 统计每一项的支持计数
     * @param subsequence
     * @param item
     * @return
     */
    private static int countSupportCount(List<String> subsequence,
            List<String> item) {   

        // System.out.print("进入countSupportCount函数!");
        int eventCount = 0;                                       //中间计数
        int supportCount = 0;                                    //支持计数
        Boolean flag = false;
        List<Integer> eventIndex = new ArrayList<Integer>();
        List<String> precursorEvent = new ArrayList<String>();
        String postiorEvent = new String();
        postiorEvent = item.get(item.size() - 1);             // 获取后继事件
        for (int k = 0; k < subsequence.size(); k++) {
            if (subsequence.get(k).equals(postiorEvent)) {   // 获取后继事件在事件子序列中的索引号
                eventIndex.add(k);
            }
        }
        if (eventIndex.size() == 0) {      // 子序列中不包含后继事件
            supportCount = 0;
        } else {                      
            for (int i = 0; i < item.size() - 1; i++) { // 获取前驱事件中的各个子事件
                precursorEvent.add(item.get(i));
            }
            //两个事件之间的小区间是否存在前驱事件,若存在则事件数加
            flag = ifExistPrecursorEvent(subsequence, precursorEvent, -1,
                    eventIndex.get(0));
            if (flag == true) {
                eventCount = 1;
            } else {
                eventCount = 0;
            }
            if (eventIndex.size() > 1) {
                for (int j = 0; j < eventIndex.size()-1; j++) {
                    flag = ifExistPrecursorEvent(subsequence, precursorEvent,
                            eventIndex.get(j), eventIndex.get(j + 1));
                    if (flag == true) {
                        eventCount++;
                    }
                }
            }
            supportCount = eventCount;
        }
        return supportCount;
    }


    /**
     * 判断子区间内是否存在前驱事件,前驱事件为一项,两项.....
     * @param subsequence  事务(子序列)
     * @param precursorEvent   前驱事件
     * @param beginIndex   子序列中一个区间的起始
     * @param endIndex    子序列中一个区间的结束
     * @return
     */
    public static Boolean ifExistPrecursorEvent(List<String> subsequence,
            List<String> precursorEvent, int beginIndex, int endIndex) {
        
        Boolean flag = false;
        Boolean havaThisItem = false;
        if (beginIndex == endIndex
                || beginIndex == (endIndex - 1)
                || (endIndex - beginIndex) - 1 < precursorEvent
                        .size()) {      // 若两个相同事件相邻,则区间不存在
            flag = false;
            return flag;
        } else {
            int i = endIndex;
            int j = precursorEvent.size() - 1;    // 记得减1,因为后面用的是索引

            int k = 0;
            // 若区间包含前驱事件则前去前驱事件序列中包含多少个事件,while循环就进行多少次,若不包含,则从后往前数,找到第一个不包含的就结束
            while (j >= 0) {     // j表示前驱事件中每个事件的索引号,从后向前依次搜索前驱事件的每个索引事件
                havaThisItem = false;
                for (k = i - 1; k > beginIndex; k--) {          // 在子序列区间中找到前驱事件中的某个事件
                    if (precursorEvent.get(j).equals(subsequence.get(k))) {// 子序列中找到前驱事件中的某个事件
                        i = k;
                        havaThisItem = true;
                        break;       
                    }
                }
                if (k == (beginIndex) && havaThisItem == false) { // 子序列区间扫描完,但在子序列中未找到前驱事件中的某个事件
                    flag = false;
                    break;
                }
                if (j == 0 && havaThisItem == true) { // 包含前驱事件中的第一项
                    flag = true;
                }
                j--;
            }
        }
        return flag;
    }

    
    /**
     * 获取二项频繁项集中所有的事件规则
     * @param fkItemSet   二项集
     * @param fItemSet    一项集
     */
    public static void getSecondConfidencedItemset(
            List<List<String>> fkItemSet, List<String> fItemSet) {
        List<List<String>> tempList = new ArrayList<List<String>>();
        double confidence = 0.0;
        List<String> anotherTempList = new ArrayList<String>();
        List<String> otherTempList = new ArrayList<String>();
        for (int i = 0; i < fkItemSet.size(); i++) {
            confidence = getSencondConfItem(fkItemSet.get(i), fkItemSet,
                    fItemSet);
            anotherTempList.add(exportConfidence);
            if (confidence > MIN_CONF) {
                System.out.print("\r\n");
                tempList.add(fkItemSet.get(i)); // lkItem.get(i)表示一个频繁项,为List<String>类型
                otherTempList.add(exportConfidence);
                for (String str : fkItemSet.get(i)) { // 输出满足置信度阈值的二项事件规则
                    System.out.print(str + "  ");
                }
                System.out.print("打印二项事件规则" + "\r\n");
                System.out.print("   " + "置信度为:" + exportConfidence + "\r\n");
            }
        }
        satisfiedConfidence.add(otherTempList); // 存储二项事件规则的置信度显示
        eventRules.add(tempList);
    }
    
    /**
     *   获取二项频繁项集中某一项的置信度
     * @param fkItem     二项集中的某一项
     * @param fkItemSet  二项集
     * @param fItemSet  一项集
     * @return
     */
    public static double getSencondConfItem(List<String> fkItem,
            List<List<String>> fkItemSet, List<String> fItemSet) {
        int currentItemNum = fkItemSet.get(0).size(); // 当前项集项数
        int precursorItemNum = 1; // 前面项集项数
        int oneItemPosition = 0; // 记录一项频繁项集的计数
        double confidence = 0.0;
        String precursorEvent = new String();
        precursorEvent = fkItem.get(currentItemNum - 2); // 获取前驱事件

        for (int i = 0; i < fItemSet.size(); i++) { // 获取前驱事件在其频繁项集中的索引
            if (fItemSet.get(i).equals(precursorEvent)) {
                oneItemPosition = i;
                break;
            }
        }
        int curerenEventPosition = findPosition(fkItem, fkItemSet);         // 找当前事件(即二项集中各项)在其频繁项集中的索引
        confidence = (double) (supporCount.get(currentItemNum - 1)
                .get(curerenEventPosition))
                / supporCount.get(precursorItemNum - 1).get(oneItemPosition);
        exportConfidence = Integer.toString(supporCount.get(currentItemNum - 1)
                .get(curerenEventPosition))
                + "/"
                + Integer.toString(supporCount.get(precursorItemNum - 1).get(
                        oneItemPosition));
        return confidence;
    }

    /**
     * 获取K项集中满足置信度的频繁项集
     * @param fkItemSet  K项集  (K>2)
     * @param fItemSet   k-1项集
     */
    public static void getConfidencedItemset(List<List<String>> fkItemSet,
            List<List<String>> fItemSet) {

        System.out.print(fkItemSet.size());
        double confidence = 0.0;
        List<List<String>> tempList = new ArrayList<List<String>>();
        List<String> anotherTempList = new ArrayList<String>();
        List<String> otherTempList = new ArrayList<String>();
        for (int i = 0; i < fkItemSet.size(); i++) {
            confidence = getConfItem(fkItemSet.get(i), fkItemSet, fItemSet);
            anotherTempList.add(exportConfidence);
            System.out.print(confidence);
            if (confidence > MIN_CONF) {
                tempList.add(fkItemSet.get(i));
                otherTempList.add(exportConfidence);
                for (String str : fkItemSet.get(i)) {             // 输出满足置信度阈值的事件规则
                    System.out.print(str+"   ");
                }
                System.out.print("   " + "置信度为:" + exportConfidence + "\r\n");
            }
        }
        satisfiedConfidence.add(otherTempList); // 存储各个事件规则的置信度显示
        eventRules.add(tempList);
    }
    /**
     * 获取第K项集中某一项的置信度(k>2),List<String> fkItem为一个频繁项
     * @param fkItem      K项集中的某一项
     * @param fkItemSet    K项集
     * @param fItemSet   k-1项集
     * @return
     */
    public static double getConfItem(List<String> fkItem,
            List<List<String>> fkItemSet, List<List<String>> fItemSet) {

        int currentItemNum = fkItemSet.get(0).size();     // 当前项集项数
        int precursorItemNum = fItemSet.get(0).size();   // 前面项集项数

        double confidence = 0.0;
        List<String> precursorEvent = new ArrayList<String>();
        for (int i = 0; i < currentItemNum - 1; i++) { // 获取前驱事件
            precursorEvent.add(fkItem.get(i));
        }

        int curerenEventPosition = findPosition(fkItem, fkItemSet); // 找当前事件在其所在频繁项集中的索引
        int precursorEventPosition = findPosition(precursorEvent, fItemSet); // 找前驱事件在其所在频繁项集中的索引

        confidence = ((double) supporCount.get(currentItemNum - 1).get(
                curerenEventPosition))
                / supporCount.get(precursorItemNum - 1).get(
                        precursorEventPosition);
        exportConfidence = Integer.toString(supporCount.get(currentItemNum - 1)
                .get(curerenEventPosition))
                + "/"
                + Integer.toString(supporCount.get(precursorItemNum - 1).get(
                        precursorEventPosition));
        return confidence;
    }

    /**
     * 找到一个项在对应项集中的位置,项集大小大于等于2
     * @param item  二项集中的某一项   
     * @param fItemSet
     * @return
     */
    public static int findPosition(List<String> item,                 
            List<List<String>> fItemSet) {
        int position = 0;
        for (int i = 0; i < fItemSet.size(); i++) {
            if (judgeEqual(item, fItemSet.get(i))) { // 判断前驱项是否和前驱项集中的项是否相同
                position = i;
                break;
            }
        }

        return position;
    }

    /**
     * 判断两个项是否相同
     * @param item   一个项
     * @param anotherItem  另一个项
     * @return
     */
    public static Boolean judgeEqual(List<String> item, List<String> anotherItem) { // 依次比较list中的每个项
        Boolean flag = true;
        for (int i = 0; i < item.size(); i++) {
            if (item.get(i).equals(anotherItem.get(i))) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    /**
     * 由K频繁项集获取K+1项候选集,通过自连接操作
     * @param fItemset     K项集,K>2
     * @return
     */
    public static List<List<String>> getNextCandidate(
                                                    
            List<List<String>> fItemset) {

        List<List<String>> nextcItemset = new ArrayList<List<String>>();
        Boolean flag = true;
        System.out.print(fItemset.size() + "\r\n");
        int ItemsetNum = fItemset.get(0).size();                   // 项数K
        for (int i = 0; i < fItemset.size(); i++) {       
            for (int j = 0; j < fItemset.size(); j++) {           // 判断连接前项的后k-1项是否和连接后项的前k-1项是否相同
                if (i != j) {
                    flag = true;
                    for (int m = 0; m < ItemsetNum - 1; m++) {
                        if (fItemset.get(i).get(m + 1).equals(fItemset.get(j).get(m))==false)// 含有不同项就终止
                                 {
                            flag = false;
                            break;
                        }
                    }
                    if (true == flag
                            && false==fItemset.get(i).get(0).equals(fItemset.get(j).get(
                                    ItemsetNum - 1))) {       // 含有相同项
                        List<String> tempList = new ArrayList<String>();
                        for (int k = 0; k < ItemsetNum; k++) {
                            tempList.add(fItemset.get(i).get(k));
                        }
                        tempList.add(fItemset.get(j).get(ItemsetNum - 1));

                        nextcItemset.add(tempList);     // 得到新候选项集
                    }
                }
            }
        }
        return nextcItemset;
    }
    /**
     * 打印所有的事件规则
     */
    public static void print() {
        System.out.print("打印侯选项集相关信息:\r\n");

        // 打印事件规则的置信度
        String eventRuleSupportFile = "/home/wdl/test/eventRuleConfidenceFile.txt";
        try {
            BufferedWriter writer = new BufferedWriter(new FileWriter(new File(
                    eventRuleSupportFile), false));
            for(int i=0;i<eventRules.size();i++){             //项集个数
                for(int j=0;j<eventRules.get(i).size();j++){  //每一个项集中项的个数      
                    for(int k=0;k<eventRules.get(i).get(j).size();k++){  
                        System.out.print(eventRules.get(i).get(j).get(k)+"\t");       
                    }    
                }    
            }
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


}

阅读全文
0 0
原创粉丝点击