(4)文本挖掘(一)——准备文本读写及对Map操作的工具类

文本挖掘是一个对具有丰富语义的文本进行分析,从而理解其所包含的内容和意义的过程。文本挖掘包含分词、文本表示、文本特征选择、文本分类、文本聚类、文档自动摘要等方面的内容。文本挖掘的具体流程图可下图所示:

我的项目是以复旦大学中文语料库和路透社英文语料库为数据集的,都是有类别的两层目录文本集。

不管你要做什么,你首先都要先读取文本,为了方便后面的操作,我写了几个工具类,这里先将文本读取Reader类、文本写入Writer类和对Map的各种操作MapUtil类。

Reader

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Angela
 */
public class Reader {

    /**
     * 获取一篇文本的编码格式,注:有时不准
     * @param filePath文本文件路径
     * @return 文本文件的编码格式
     */
    public static String getCharset(String filePath){
        String charset = null;
        try{
            BufferedInputStream bin = new BufferedInputStream(
                    new FileInputStream(filePath));
            int p = (bin.read() << 8) + bin.read();
            switch (p) {
                case 0xefbb:
                    charset = "UTF-8";
                    break;
                case 0xfffe:
                    charset = "Unicode";
                    break;
                case 0xfeff:
                    charset = "UTF-16BE";
                    break;
                default:
                    charset = "GBK";
            }
        } catch (FileNotFoundException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
        return charset;
    }

    /**
     * 读取一篇文本的全部内容
     * @param filePath 还未分词的文本
     * @return 无换行的文本内容,读取的内容用于后面的分词
     */
    public static String read(String filePath){
        String content="";
        //String charset=getCharset(filePath);
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(filePath),"gb2312"));
            String s;
            while((s=br.readLine())!=null){
                content+=s;
            }
            br.close();
        }catch (IOException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
        return content;
    }

    /**
     * 一行一个词地读取一篇文本,得到特征集
     * @param filePath
     * @return 读取分词后的文本,得到出现在文本中的所有不重复的特征Set
     */
    public static Set<String> toSet(String filePath){
        Set<String> set=new HashSet<String>();
        //String charset=getCharset(filePath);
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(filePath),"utf-8"));
            String s;
            while((s=br.readLine())!=null){
                set.add(s);
            }
            br.close();
        }catch (IOException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
        return set;
    }

    /**
     * 一行一个词地读取一篇文本,得到特征列表,有重复的
     * @param filePath
     * @return 读取分词后的文本,得到出现在文本中的所有特征(有重复的)List
     */
    public static List<String> toList(String filePath){
        List<String> list=new ArrayList<String>();
        //String charset=getCharset(filePath);
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(filePath),"utf-8"));
            String s;
            while((s=br.readLine())!=null){
                list.add(s);
            }
            br.close();
        }catch (IOException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
        return list;
    }

    /**
     * 读取文件内容,返回一个特征-权重的Map
     * @param filePath
     * @return
     */
    public static Map<String,Integer> toIntMap(String filePath){
        Map<String,Integer> map=new HashMap<String,Integer>();
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(filePath),"utf-8"));
            String str;
            while((str=br.readLine())!=null){//特征
                String[] s=str.split(",");
                String key=s[0];//特征
                int value=Integer.parseInt(s[1]);//特征值
                map.put(key, value);
            }
            br.close();
        }catch (IOException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
        return map;
    }

    /**
     * 读取文件内容,返回一个特征-权重的Map
     * @param filePath
     * @return
     */
    public static Map<String,Double> toDoubleMap(String filePath){
        Map<String,Double> map=new HashMap<String,Double>();
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(filePath),"utf-8"));
            String str;
            while((str=br.readLine())!=null){//特征
                String[] s=str.split(",");
                String key=s[0];//特征
                double value=Double.parseDouble(s[1]);//特征值
                map.put(key, value);
            }
            br.close();
        }catch (IOException ex) {
            Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
        }
        //return map;
        return MapUtil.descend(map);
    }   

    /**
     * 获取分词后的文本集
     * @param filePath
     * @return
     */
    public static Map<String,Set<String>> readDataSet(String filePath){
        Map<String,Set<String>> map=new HashMap<String,Set<String>>();
        File path=new File(filePath);
        File[] files=path.listFiles();//类别
        for(File file: files){
            String label=file.getName();
            File[] texts=file.listFiles();//文本
            for(File text: texts){
                map.put(label+File.separator+text.getName(),
                        toSet(text.getAbsolutePath()));
            }
        }
        return map;
    }    

    /**
     * 获取文本集的TFIDF集
     * @param filePath
     * @return
     */
    public static Map<String,Map<String,Double>> readTFIDF(String filePath){
        Map<String,Map<String,Double>> map=new HashMap<String,Map<String,Double>>();
        File path=new File(filePath);
        File[] files=path.listFiles();//类别
        for(File file: files){
            String label=file.getName();
            File[] texts=file.listFiles();//文本
            for(File text: texts){
                map.put(label+File.separator+text.getName(),
                        toDoubleMap(text.getAbsolutePath()));
            }
        }
        return map;
    }  

}

Writer类

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Angela
 */
public class Writer {

    /**
     * 传入一篇文本分词后的特征表List,将List的内容一行一个特征地写入
     * tarPath文件中(有重复)
     * @param list 一篇文本分词后的结果:特征列表List
     * @param tarPath 保存路径
     */
    public static void saveList(List<String> list,String tarPath){
        try{
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(tarPath)));
            for(String s: list){
                bw.write(s);
                bw.newLine();
            }
            bw.flush();
            bw.close();
        } catch (IOException ex) {
            Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 传入一篇文本分词后的特征集Set,将Set的内容一行一个特征地
     * 写入tarPath文件中(无重复的)
     * @param set 特征集Set
     * @param tarPath 保存路径
     */
    public static void saveSet(Set<String> set,String tarPath){
        try{
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(tarPath)));
            for(String s: set){
                bw.write(s);
                bw.newLine();
            }
            bw.flush();
            bw.close();
        } catch (IOException ex) {
            Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 传入一篇文本分词后的特征集Map,将Map的内容一行一个地写入
     * tarPath文件中(无重复的)
     * @param map 特征集Map
     * @param tarPath 保存路径,将特征-特征值Map内容保存在tarPath文件中
     */
    public static <K, V extends Number> void saveMap(Map<K, V> map,String tarPath){
        try{
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(tarPath)));
            for(Map.Entry<K,V> me: map.entrySet()){
                bw.write(me.getKey()+","+me.getValue());
                bw.newLine();
            }
            bw.flush();
            bw.close();
        } catch (IOException ex) {
            Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 读取分词后的文本集,保存其TF结果,整个文本集的DF和IDF结果
     * 同时计算总文本数,总词数,文本平均词数
     * @param segmentPath 分词后的文本集路径
     * @param savePath TF保存路径
     * @param DFSavePath DF保存路径
     * @param IDFSavePath IDF保存路径
     */
    public static void saveTFDFIDF(String segmentPath,String savePath,
            String DFSavePath,String IDFSavePath){
        File path=new File(savePath);
        if(!path.exists()) path.mkdir();
        File file=new File(segmentPath);
        File[] labels=file.listFiles();//类别
        int textNum=0;//总文本数
        long wordNum=0;//文本集的总词数
        Map<String,Integer> DF=new HashMap<String,Integer>();
        for(File label: labels){
            String labelName=label.getName();
            String tarLabel=savePath+File.separator+labelName;
            File labelpath=new File(tarLabel);
            if(!labelpath.exists()) labelpath.mkdir();
            File[] texts=label.listFiles();//文本
            textNum+=texts.length;
            for(File text: texts){
                String tarPath=tarLabel+File.separator+text.getName();
                //每篇文本的TF集合
                Map<String,Integer> TF=new HashMap<String,Integer>();
                List<String> words=Reader.toList(text.getAbsolutePath());
                for(String word: words){
                    //计算TF
                    if(TF.containsKey(word)) TF.put(word, TF.get(word)+1);
                    else TF.put(word, 1);
                }
                TF=MapUtil.descend(TF);
                saveMap(TF,tarPath);
                for(Map.Entry<String,Integer> me: TF.entrySet()){
                    String f=me.getKey();
                    wordNum+=me.getValue();
                    //计算DF
                    if(DF.containsKey(f)) DF.put(f, DF.get(f)+1);
                    else DF.put(f, 1);
                }
            }
        }
        DF=MapUtil.descend(DF);//对DF进行降序排序
        saveMap(DF,DFSavePath);//保存DF结果
        System.out.println("总文本数:"+textNum);
        System.out.println("总词数:"+wordNum);
        System.out.println("文本平均词数:"+wordNum*1.0/textNum);
        Map<String,Double> IDF=new HashMap<String,Double>();
        for(Map.Entry<String,Integer> me: DF.entrySet()){
            IDF.put(me.getKey(), Math.log(textNum*1.0/me.getValue()));
        }
        saveMap(IDF,IDFSavePath);
    }          

    /**
     * 根据arff文件要求的格式,把数据写入tarPath这个arff文件
     * 方便进行weka测试
     * @param TFIDF TFIDF数据集
     * @param featureSet 特征列表
     * @param labelList 类别集
     * @param tarPath 保存路径
     */
    public static void saveAsArff(Map<String,Map<String,Double>> TFIDF,
            Set<String> featureSet,String[] labelList,String tarPath){
        //保存的文件名
        String fileName=tarPath.substring(tarPath.lastIndexOf(File.separator)+1);
        try{
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(tarPath)));
            bw.write("@relation "+fileName);//relation需与文件名保存一致
            bw.newLine();
            for(String feature: featureSet){
                //将class改成class1
                if(feature.equals("class")){
                    feature="class1";
                }
                bw.write("@attribute "+feature+" real");//特征
                bw.newLine();
            }
            int k=labelList.length;
            bw.write("@attribute class {");//类别
            for(int i=0;i<k-1;i++){
                bw.write(labelList[i]+",");
            }
            bw.write(labelList[k-1]+"}");
            bw.newLine();
            bw.write("@data");//每一篇文本的对应特征的TFIDF权重
            bw.newLine();
            for(Map.Entry<String,Map<String,Double>> me: TFIDF.entrySet()){
                String path=me.getKey();
                String label=path.substring(0,path.lastIndexOf(File.separator));
                Map<String,Double> weight=me.getValue();
                for(String f: featureSet){
                    if(weight.containsKey(f)){
                        bw.write(weight.get(f)+",");
                    }else{
                        bw.write(0+",");
                    }
                }
                bw.write(label);
                bw.newLine();
            }
            bw.flush();
            bw.close();
        }catch (IOException ex) {
            Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

        /**
     * 根据csv文件要求的格式,把数据写入tarPath这个csv文件
     * @param TFIDF TFIDF数据集
     * @param featureSet 特征列表
     * @param tarPath 保存路径
     */
    public static void saveAsCSV(Map<String,Map<String,Double>> TFIDF,
            Set<String> featureSet,String tarPath){
        //将class改成class1
        if(featureSet.contains("class")){
            featureSet.remove("class");
            featureSet.add("class1");
        }
        try{
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(tarPath)));
            for(String feature: featureSet){
                bw.write(feature+",");//特征
            }
            bw.write("class");//类别
            bw.newLine();
            for(Map.Entry<String,Map<String,Double>> me: TFIDF.entrySet()){
                String path=me.getKey();
                String label=path.substring(0,path.lastIndexOf(File.separator));
                Map<String,Double> weight=me.getValue();
                for(String f: featureSet){
                    if(weight.containsKey(f)){
                        bw.write(weight.get(f)+",");
                    }else{
                        bw.write(0+",");
                    }
                }
                bw.write(label);
                bw.newLine();
            }
            bw.flush();
            bw.close();
        }catch (IOException ex) {
            Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 读取已经进行词干提取并去掉停用词的英文语料库,将文本保存在其相应类别下
     * @param filePath 语料库txt路径
     * @param tarDir 保存目录
     */
    public static void saveFile(String filePath,String tarDir){
        File path=new File(tarDir);
        if(!path.exists())  path.mkdir();
        try{
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream(filePath),"utf-8"));
            String s;
            int count=1;
            while((s=br.readLine())!=null){
                String[] content=s.split("[\\s]");
                String tarLabel=tarDir+File.separator+content[0];
                File label=new File(tarLabel);
                if(!label.exists())     label.mkdir();
                String tarPath=tarLabel+File.separator+count+".txt";
                BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
                        new FileOutputStream(tarPath)));
                int len=content.length;
                for(int i=1;i<len;i++){
                    bw.write(content[i]);
                    bw.newLine();
                }
                bw.flush();
                bw.close();
                count++;
            }
            br.close();
        }catch (IOException ex) {
            Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * 主函数,保存分词后的DF、IDF结果
     * @param args
     */
    public static void main(String args[]){
        String segmentPath="data\\r8-train-stemmed";
        String TFPath="data\\r8trainTF";
        String DFSavePath="data\\r8trainDF.txt";
        String IDFSavePath="data\\r8trainIDF.txt";
        saveTFDFIDF(segmentPath,TFPath,DFSavePath,IDFSavePath);
        /*String filePath="data\\r8-test-stemmed.txt";
        String tarDir="data\\r8-test-stemmed";
        saveFile(filePath,tarDir);*/
    }

}

MapUtil类

import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

/**
 *
 * @author Angela
 */
public class MapUtil {

    /**对Map按键值升序排序**/
    public static <K, V extends Comparable<? super V>>
            Map<K, V> ascend( Map<K, V> map){
        //将map.entrySet()转换成list
        LinkedList<Map.Entry<K, V>> list =
                new LinkedList<Map.Entry<K, V>>( map.entrySet() );
        //然后通过比较器来实现排序
        Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
            //升序排序
            public int compare( Map.Entry<K, V> o1, Map.Entry<K, V> o2 ){
                return (o1.getValue()).compareTo( o2.getValue() );
            }
        } );
        Map<K, V> result = new LinkedHashMap<K, V>();
        for (Map.Entry<K, V> entry : list) {
            result.put( entry.getKey(), entry.getValue() );
        }
        return result;
    }  

    /**对Map按键值降序排序**/
    public static <K, V extends Comparable<? super V>>
            Map<K, V> descend( Map<K, V> map){
        //将map.entrySet()转换成list
        LinkedList<Map.Entry<K, V>> list =
                new LinkedList<Map.Entry<K, V>>( map.entrySet() );
        //然后通过比较器来实现排序
        Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
            //降序排序
            public int compare( Map.Entry<K, V> o1, Map.Entry<K, V> o2 ){
                return (o2.getValue()).compareTo( o1.getValue() );
            }
        } );
        Map<K, V> result = new LinkedHashMap<K, V>();
        for (Map.Entry<K, V> entry : list) {
            result.put( entry.getKey(), entry.getValue() );
        }
        return result;
    }  

    /**
     * 取键值大于最小阈值并且小于最大阈值的map子集
     * @param map
     * @param minThreshold 最小阈值
     * @param maxThreshold 最大阈值
     * @return
     */
    public static <K, V extends Comparable<? super V>> Map<K,V> getSubMap(
            Map<K,V> map,V minThreshold,V maxThreshold){
        Map<K,V> temp=new HashMap<K,V>();
        for(Map.Entry<K, V> me: map.entrySet()){
            V value=me.getValue();
            if(value.compareTo(minThreshold)>=0
                    &&value.compareTo(maxThreshold)<=0){
                map.put(me.getKey(), value);
            }
        }
        return map;
    }

    /**
     * 返回键值大于最小阈值的map子集
     * @param map
     * @param minThreshold 最小阈值
     * @return
     */
    public static <K, V extends Comparable<? super V>> Map<K,V> getSubMap(
            Map<K,V> map,V minThreshold){
        Map<K,V> temp=new HashMap<K,V>();
        for(Map.Entry<K, V> me: map.entrySet()){
            V value=me.getValue();
            if(value.compareTo(minThreshold)>=0){
                map.put(me.getKey(), value);
            }
        }
        return map;
    }

    /**
     * 降序排序,选前num的特征集合
     * @param map 特征-权重集
     * @param num 个数
     * @return 降序排序后前num的特征子集
     */
    public static <K, V extends Comparable<? super V>> Map<K,V> getSubMap(
            Map<K,V> map,int num){
        Map<K,V> temp=new HashMap<K,V>();
        map=descend(map);
        Set<Map.Entry<K,V>> set = map.entrySet();
        Iterator<Map.Entry<K,V>> it = set.iterator();
        int count=0;
        while(count<num&&it.hasNext()){
            Map.Entry<K,V> me = it.next();
            V value=me.getValue();
            temp.put(me.getKey(), value);
            count++;
        }
        return temp;
    }

    /**
     * 降序排序,选前percent的特征集合
     * @param map 特征-权重集
     * @param percent 百分比
     * @return 降序排序后前percent的特征子集
     */
    public static <K, V extends Comparable<? super V>> Map<K,V> getPercentMap(
            Map<K,V> map,double percent){
        if(percent>1||percent<0){
            System.out.println("请输入0~1之间的小数");
            System.exit(0);
        }
        int num=(int)(map.size()*percent);
        return getSubMap(map,num);
    }

    /**
     * 打印map的前num个数据
     * @param map 排序后的特征-权重集
     * @param num 个数
     */
    public static <K, V extends Comparable<? super V>>
            void print(Map<K,V> map,int num){
        Set<Map.Entry<K,V>> temp = map.entrySet();
        Iterator<Map.Entry<K,V>> it = temp.iterator();
        int count=0;
        while(it.hasNext()&&count<num){
            Map.Entry<K,V> me = it.next();
            System.out.println(me.getKey()+" "+me.getValue());
            count++;
        }
    }

}
时间: 2024-08-09 03:56:22

(4)文本挖掘(一)——准备文本读写及对Map操作的工具类的相关文章

Node.js读写中文内容文件操作

由于Node.js仅支持如下编码:utf8, ucs2, ascii, binary, base64, hex,并不支持中文GBK或GB2312之类的编码, 因此如果要读写中文内容,必须要用额外的模块:iconv-lite 注:Node的iconv模块,仅支持linux,不支持Windows,因此要用纯js的iconv-lite,另:作者说iconv-lite的性能更好,具体参考git站点:iconv-lite 注2:我在测试读写文件时,始终无法把中文写入文件,一直乱码,读取正常,后来同事帮我发

list集合、txt文件对比的工具类和文件读写工具类

工作上经常会遇到处理大数据的问题,下面两个工具类,是在处理大数据时编写的:推荐的是使用map的方式处理两个list数据,如果遇到list相当大数据这个方法就起到了作用,当时处理了两个十万级的list,使用改方法的变种搞定. 1.txt文件.list集合比较工具 <span style="font-family:KaiTi_GB2312;font-size:18px;">package com.hudong.util.other; import java.util.Colle

(Android review)文件的读写(对File的操作)

Android中对操作的文件主要可以分为:File.XML.SharedPreference. 这篇博客主要介绍对File的操作: 1.MainActivity package com.example.filetest; import android.os.Bundle; import android.os.Environment; import android.app.Activity; import android.view.Menu; import android.view.View; i

TRTOS +TQFS多个任务同时读写文件的互斥操作

#include <Include.h> #include <TQFS_File.h> #include <stdlib.h> /******************************************************************************* Func:删除文件标准文件路径 .eg /example/新建文件.txt Date:2014-7-27 Note:FileSize=0时为不确定文件长度 **************

Android之文件读写工具类

本工具类永久维护,永久更新,如果各位读者发现有bug或者不合理之处,欢迎指正,博主将第一时间改正. 以下是主要内容,本类主要功能有: 1.创建文件功能: 2.向文件中写入字节数组: 3.向文件中写入字符串: 4.从文件中读取字节数组: 5.从文件中读取字符串: import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; /** * 文件读写工具类 * * @author bear *

文本框工具类--TextViewUtil

本工具类功能: 给TextView设置部分大小 给TextView设置部分颜色 给TextView设置下划线 半角转换为全角 去除特殊字符或将所有中文标号替换为英文标号 /** * Created by peng on 2015/06/16. * 文本框工具类 */ public class TextViewUtil { //给TextView设置部分大小 public static void setPartialSize(TextView tv, int start, int end, int

java读写文件(可当工具类保存。解决乱码)

//读文件 public static String ReadFile(String path) { File file = new File(path); BufferedReader reader = null; String laststr = ""; try { reader = new BufferedReader(new FileReader(file)); String tempString = null; while ((tempString = reader.read

Android 文件读写工具类

自己写的工具类,写的不好,慢慢修改. 记得加上权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> package com.sy.utils; import android.con

QSettings配置读写-win注册表操作-ini文件读写

版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSettings配置读写-win注册表操作-ini文件读写     本文地址:http://techieliang.com/2017/12/674/ 文章目录 1. 介绍 2. 创建配置文件  2.1. 配置格式  2.2. 作用域  2.3. 关于组织.程序名 3. 配置文件读写 4. 范例  4.1. win下SystemScope.IniFormat  4.2. win下UserSc