月度归档: 2015 年 6 月

  • C++基于Windows的音频采集

    C++基于Windows的音频采集

    #include "stdafx.h"
    
    #include <time.h>
    #include <windows.h>
    #include<mmsystem.h>
    #include<mmreg.h>
    #pragma  comment(lib, "winmm.lib")
    
    struct RIFF_HEADER//文件类型
    {
        char szRiffID[4]; // 'R','I','F','F'
        DWORD dwRiffSize;//DWORD最大可容纳4GB的文件大小=FILE_LENGTH-8(即减去此数据结构大小)
        char szRiffFormat[4]; // 'W','A','V','E'
    };
    
    struct WAVE_FORMAT
    {
        WORD wFormatTag;
        WORD wChannels;
        DWORD dwSamplesPerSec;
        DWORD dwAvgBytesPerSec;
        WORD wBlockAlign;
        WORD wBitsPerSample;
    };
    
    struct FMT_BLOCK
    {
        char szFmtID[4]; // 'f','m','t',' '
        DWORD dwFmtSize;
        WAVE_FORMAT wavFormat;
    };
    
    struct DATA_BLOCK
    {
        char szDataID[4]; // 'd','a','t','a'
        DWORD dwDataSize;
    };
    
    //struct FACT_BLOCK//可先项 一般可不用
    //{
    //    char szFactID[4]; // 'f','a','c','t'
    //    DWORD dwFactSize;
    //};
    
    WAVEFORMATEX pwfx; //声音格式
    
    
    #define MAX_RUN_COUNT 4
    #define BUFFER_COUNT 4
    #define MAX_BUFF_SOUNDSIZE 10240
    FILE *fptmp;
    CHAR m_cBufferIn[BUFFER_COUNT][MAX_BUFF_SOUNDSIZE];
    WAVEHDR m_pWaveHdrIn[BUFFER_COUNT];
    HWAVEIN phwi; //设备句柄
    
    bool is_stop = false;
    
    
    void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh, DWORD nSampleRate, WORD BitsPerSample)
    {
        m_WaveFormat->wFormatTag = WAVE_FORMAT_PCM;
        m_WaveFormat->nChannels = nCh;
        m_WaveFormat->nSamplesPerSec = nSampleRate;
        m_WaveFormat->nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample / 8;
        m_WaveFormat->nBlockAlign = m_WaveFormat->nChannels * BitsPerSample / 8;
        m_WaveFormat->wBitsPerSample = BitsPerSample;
        m_WaveFormat->cbSize = 0;
    }
    
    DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
    {
        switch (uMsg)
        {
        case WIM_OPEN: //打开设备时消息,在此期间我们可以进行一些初始化工作
            printf("\n设备已经打开...\n");
            break;
    
        case WIM_DATA: //当缓存已满或者停止录音时的消息,处理这个消息可以对缓存进行重新分配,实现不限长度录音
        {
            WAVEHDR*p = ((PWAVEHDR)dwParam1); // 这就是采集到的数据指针
            DWORD len = p->dwBytesRecorded; // 这就是采集到的数据长度
           
    
            int i = p->dwUser;
            if (is_stop) //停止
            {
                waveInUnprepareHeader(phwi, p, sizeof(WAVEHDR)); //释放
                return 0;
            }
            
            printf("\n缓冲区%d存满...\n", p->dwUser);
            fwrite(&m_cBufferIn[i], 1, p->dwBytesRecorded, fptmp);
            waveInUnprepareHeader(phwi, p, sizeof(WAVEHDR)); //释放
            
    
    
            p->lpData = m_cBufferIn[i];
            p->dwBufferLength = MAX_BUFF_SOUNDSIZE;
            p->dwBytesRecorded = 0;
            p->dwUser = i;
            p->dwFlags = 0;
            waveInPrepareHeader(phwi, p, sizeof(WAVEHDR)); //准备内存块录音
            waveInAddBuffer(phwi, p, sizeof(WAVEHDR)); //增加内存块
    
            break;
        }
        case WIM_CLOSE: //关闭录音设备时的消息
            printf("\n设备已经关闭...\n");
            break;
        default:
            break;
        }
        return 0;
    }
    
    //录音函数
    void Start()
    {
        //获取声卡数
        int count = waveInGetNumDevs();//1
        printf("\n音频输入数量:%d\n", count);
    
        //获取声音输入设备
        WAVEINCAPS waveIncaps;
        MMRESULT mmResult = waveInGetDevCaps(0, &waveIncaps, sizeof(WAVEINCAPS));//2
        printf("\n音频输入设备:%s\n", waveIncaps.szPname);
    
        //如果正确获取到输入设备
        if (MMSYSERR_NOERROR == mmResult)
        {
            /// HWAVEIN phwi; //设备句柄
            //  WAVEFORMATEX pwfx;
            WaveInitFormat(&pwfx, 1, 8000, 8);
            printf("\n请求打开音频输入设备");
            printf("\n采样参数:单声道 8kHz 8bit\n");
            //打开录音设备
            mmResult = waveInOpen(&phwi, WAVE_MAPPER, &pwfx, (DWORD)(MicCallback), NULL, CALLBACK_FUNCTION);//3
    
            //如果正确打开了设备
            if (MMSYSERR_NOERROR == mmResult)
            {
                for (int i = 0; i < BUFFER_COUNT; i++)
                {
                    m_pWaveHdrIn[i].lpData = m_cBufferIn[i];
                    m_pWaveHdrIn[i].dwBufferLength = MAX_BUFF_SOUNDSIZE;
                    m_pWaveHdrIn[i].dwBytesRecorded = 0;
                    m_pWaveHdrIn[i].dwUser = i;
                    m_pWaveHdrIn[i].dwFlags = 0;
                    mmResult = waveInPrepareHeader(phwi, &m_pWaveHdrIn[i], sizeof(WAVEHDR));//4
                    printf("\n准备缓冲区%d\n", i + 1);
                }
    
                //数据头准备完成
                if (MMSYSERR_NOERROR == mmResult)
                {
                    for (int i = 0; i < BUFFER_COUNT; i++)
                    {
                        mmResult = waveInAddBuffer(phwi, &m_pWaveHdrIn[i], sizeof(WAVEHDR));//5
                        printf("\n将缓冲区%d加入音频输入设备\n", i + 1);
                    }
    
                    //数据块准备完成
                    if (MMSYSERR_NOERROR == mmResult)
                    {
                        //开始录音
                        mmResult = waveInStart(phwi);//6
                        printf("\n请求开始录音\n");
                    }
                }
            }
        }
    }
    
    void Stop()
    {
        is_stop = true;
        Sleep(3000); //等待录音完成
    
        printf("Start Stop\n");
        waveInStop(phwi);
    
        printf("Start Reset\n");
        waveInReset(phwi);
    
        printf("Start Close\n");
        waveInClose(phwi);
    
        fclose(fptmp);
    }
    
    void Save()
    {
        long len = 0;
        char *buf = NULL;
        FILE *fp;
        if (fopen_s(&fp, "temp.dat", "rb") == 0)
        {
            fseek(fp, 0, SEEK_END);;
            len = ftell(fp);
            fseek(fp, 0, SEEK_SET);
            buf = new char[len + 1];
            memset(buf, 0, sizeof(char)*(len + 1));
            fread(buf, len, 1, fp);
            fclose(fp);
        }
        if (buf == NULL)
        {
            printf("save error\n");
            return;
        }
    
        if (fopen_s(&fp, "output.wav", "wb") == 0)
        {
            RIFF_HEADER riff;
            WAVE_FORMAT wform;
            FMT_BLOCK fmt;
            //FACT_BLOCK fact;
            DATA_BLOCK data;
            memset(&riff, 0, sizeof(RIFF_HEADER));
            memset(&wform, 0, sizeof(WAVE_FORMAT));
            memset(&fmt, 0, sizeof(FMT_BLOCK));
            //memset(&fact, 0, sizeof(FACT_BLOCK));
            memset(&data, 0, sizeof(DATA_BLOCK));
    
            fmt.wavFormat.wFormatTag = WAVE_FORMAT_PCM;//1
            fmt.wavFormat.dwAvgBytesPerSec = pwfx.nAvgBytesPerSec;
            fmt.wavFormat.dwSamplesPerSec = pwfx.nSamplesPerSec;
            fmt.wavFormat.wBitsPerSample = pwfx.wBitsPerSample;
            fmt.wavFormat.wBlockAlign = pwfx.nBlockAlign;
            fmt.wavFormat.wChannels = pwfx.nChannels;
    
            memcpy(fmt.szFmtID, "fmt ", 4);
            fmt.dwFmtSize = 16;//一般情况下为16,如有附加信息为18
            memcpy(data.szDataID, "data", 4);
            data.dwDataSize = len;
    
    
            riff.dwRiffSize = (len + sizeof(FMT_BLOCK) + sizeof(DATA_BLOCK));
            memcpy(riff.szRiffFormat, "WAVE", 4);
            memcpy(riff.szRiffID, "RIFF", 4);
    
            fwrite(&riff, sizeof(RIFF_HEADER), 1, fp);//写RIFF_HEADER
            fwrite(&fmt, sizeof(FMT_BLOCK), 1, fp);//写FMT_BLOCK
            fwrite(&data, sizeof(DATA_BLOCK), 1, fp);//写数据头 DATA_BLOCK
    
            fwrite(buf, len, 1, fp);
    
            fclose(fp);
        }
    }
    
    
    DWORD WINAPI TimeThread(LPVOID wPame)
    {
        Sleep(10000);
        return 0;
    }
    
    
    int main(void)
    {
        errno_t errno;
        errno = fopen_s(&fptmp, "temp.dat", "wb");
        if (errno != 0)
        {
            printf("临时文件创建失败..\n");
            return 0;
        }
    
        Start();
    
        HANDLE hThread = CreateThread(NULL, NULL, TimeThread, NULL, NULL, NULL);
        WaitForSingleObject(hThread, INFINITE); //等待计时线程执行完成
    
        Stop();
        Save();
    
        system("pause");
        return 0;
    }
  • 把HDC保存成图片

    把HDC保存成图片,做法如下:

    先调用CopyDCToBitmap把HDC转成HBITMAP, 然后调用 SaveBmpSaveImg

    BOOL SaveBmp (HBITMAP hBitmap, CString FileName)
    {
        HDC   hDC;
        //当前分辨率下每象素所占字节数  
        int   iBits;
        //位图中每象素所占字节数  
        WORD  wBitCount;
        //定义调色板大小,位图中像素字节大小,位图文件大小,写入文件字节数
        DWORD dwPaletteSize = 0, dwBmBitsSize = 0, dwDIBSize = 0, dwWritten = 0;
        //位图属性结构    
        BITMAP   Bitmap;
        //位图文件头结构  
        BITMAPFILEHEADER   bmfHdr;
        //位图信息头结构    
        BITMAPINFOHEADER   bi;
        //指向位图信息头结构      
        LPBITMAPINFOHEADER lpbi;
        //定义文件,分配内存句柄,调色板句柄    
        HANDLE  fh, hDib, hPal, hOldPal = NULL;
    
        //计算位图文件每个像素所占字节数    
        hDC = CreateDC(_T("DISPLAY"), NULL, NULL , NULL);
        iBits = GetDeviceCaps( hDC, BITSPIXEL) * GetDeviceCaps (hDC , PLANES);
        DeleteDC( hDC);
        if (iBits <= 1) wBitCount = 1;
        else if (iBits <= 4) wBitCount = 4;
        else if (iBits <= 8) wBitCount = 8;
        else wBitCount = 24;
    
        GetObject(hBitmap, sizeof(Bitmap), (LPSTR)& Bitmap);
        bi.biSize = sizeof( BITMAPINFOHEADER);
        bi.biWidth = Bitmap. bmWidth;
        bi.biHeight = Bitmap. bmHeight;
        bi.biPlanes = 1;
        bi.biBitCount = wBitCount;
        bi.biCompression = BI_RGB;
        bi.biSizeImage = 0;
        bi.biXPelsPerMeter = 0;
        bi.biYPelsPerMeter = 0;
        bi.biClrImportant = 0;
        bi.biClrUsed = 0;
    
        dwBmBitsSize = (( Bitmap. bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;
    
        //   为位图内容分配内存    
        hDib = GlobalAlloc( GHND, dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER ));
        lpbi = (LPBITMAPINFOHEADER) GlobalLock(hDib );
        *lpbi = bi;
    
        //   处理调色板      
        hPal = GetStockObject( DEFAULT_PALETTE);
        if (hPal)
        {
            hDC = :: GetDC( NULL);
            //hDC   =   m_pDc->GetSafeHdc();  
            hOldPal = :: SelectPalette(hDC , (HPALETTE)hPal, FALSE);
            RealizePalette(hDC );
        }
        //   获取该调色板下新的像素值    
        GetDIBits( hDC, hBitmap, 0, ( UINT)Bitmap .bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER )
            + dwPaletteSize, (BITMAPINFO *)lpbi , DIB_RGB_COLORS);
    
        //   恢复调色板      
        if (hOldPal)
        {
            :: SelectPalette(hDC , (HPALETTE)hOldPal, TRUE);
            RealizePalette(hDC );
            :: ReleaseDC(NULL , hDC );
        }
    
        //   创建位图文件      
        fh = CreateFile( FileName, GENERIC_WRITE, 0, NULL , CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN , NULL);
    
        if (fh == INVALID_HANDLE_VALUE)
            return FALSE;
    
        //   设置位图文件头    
        bmfHdr.bfType = 0x4D42;   //   ;BM;
        dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof( BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize ;
        bmfHdr.bfSize = dwDIBSize;
        bmfHdr.bfReserved1 = 0;
        bmfHdr.bfReserved2 = 0;
        bmfHdr.bfOffBits = ( DWORD)sizeof (BITMAPFILEHEADER) + (DWORD)sizeof (BITMAPINFOHEADER) + dwPaletteSize;
        //   写入位图文件头
        WriteFile( fh, ( LPSTR)&bmfHdr , sizeof (BITMAPFILEHEADER), &dwWritten, NULL);
        //   写入位图文件其余内容
        WriteFile( fh, ( LPSTR)lpbi , dwDIBSize , &dwWritten , NULL);
        //   清除
        GlobalUnlock( hDib);
        GlobalFree( hDib);
        CloseHandle( fh);
    
        return TRUE;
    }
    
    
    // 保存成JPG文件
    BOOL SaveImg (HBITMAP hBitmap, CString imgFile)
    {
        BITMAP bm;
        int width, height;
        GetObject(hBitmap, sizeof(BITMAP), & bm);
        width = bm.bmWidth;
        height = bm.bmHeight;
        CDC memDC;
        memDC.CreateCompatibleDC( NULL);
        memDC.SelectObject(hBitmap);
    
        CImage image;
        image.Create(width, height, 32);
        BitBlt( image. GetDC(), 0, 0, width, height, memDC. m_hDC, 0, 0, SRCCOPY );
    
        HRESULT hResult = image. Save(imgFile );
        //image.Save(_T("new.bmp"), Gdiplus::ImageFormatBMP);   // 保存成bmp
    
        image.ReleaseDC();
        memDC.DeleteDC();
        return SUCCEEDED( hResult);
    }
    
    
    HBITMAP CopyDCToBitmap (HDC hScrDC, LPRECT lpRect)
    {
        HDC  hMemDC;
        //   屏幕和内存设备描述表  
        HBITMAP hBitmap, hOldBitmap;
        //   位图句柄  
        int  nX, nY, nX2, nY2;
        //   选定区域坐标  
        int  nWidth, nHeight;
        //   位图宽度和高度  
    
        //   确保选定区域不为空矩形  
        if (IsRectEmpty( lpRect))
            return   NULL;
    
        //   获得选定区域坐标  
        nX = lpRect->left;
        nY = lpRect->top;
        nX2 = lpRect->right;
        nY2 = lpRect->bottom;
        nWidth = nX2 - nX;
        nHeight = nY2 - nY;
        //   为屏幕设备描述表创建兼容的内存设备描述表  
        hMemDC = CreateCompatibleDC( hScrDC);
        //   创建一个与屏幕设备描述表兼容的位图,函数需要与CreateCompatibleDC配合使用  
        hBitmap = CreateCompatibleBitmap( hScrDC, nWidth, nHeight);
        //   把新位图选到内存设备描述表中  
        hOldBitmap = ( HBITMAP)SelectObject (hMemDC , hBitmap );
        //   把屏幕设备描述表拷贝到内存设备描述表中
        //   StretchBlt函数从源矩形中复制一个位图到目标矩形,必要时按目前目标设备设置的模式进行图像的拉伸或压缩。
        StretchBlt( hMemDC, 0, 0, nWidth, nHeight, hScrDC, nX, nY, nWidth, nHeight, SRCCOPY);  // SRCCOPY
        //BitBlt(hMemDC,   0,   0,   nWidth,   nHeight,hScrDC,   nX,   nY,   SRCCOPY);  
        //   得到屏幕位图的句柄    
    
        hBitmap = (HBITMAP) SelectObject(hMemDC , hOldBitmap );
        //   清除    
    
        //DeleteDC(hScrDC);  
        DeleteDC( hMemDC);
        DeleteObject( hOldBitmap);
        //   返回位图句柄  
        return   hBitmap;
    }
  • HPSocket中SendSmallFile的使用

    HPSocket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,这里记录的是通过 HPSocket 发送小文件的功能,代码如下:

    p-> GetCurrentImage();
    
    CFile file (_T("$shs.jpg"), CFile::modeRead );
    auto uLen = file. GetLength();
    file. Close();
    
    TPkgHeader * header = new TPkgHeader ();
    header-> seq = NET_SSH_SCREEN;
    header-> body_len = uLen;
    
    WSABUF buf ;
    buf. len = sizeof (TPkgHeader );
    buf. buf = (CHAR *)header ;
    
    p-> m_pSocket-> GetTcpPullClientPtr()->SendSmallFile (_T("$shs.jpg"), &buf, NULL );
  • VC跨进程操作SysListview32控件

    VC跨进程操作SysListview32控件,代码如下:

    bool CTaskManager::StockCodeIsExist(CString stockCode)
    {
        HWND hMain = CWndHelper::GetMainWnd();
        HWND hListview = ::FindWindowEx(hMain, NULL, _T("SysListView32"), NULL);
        ASSERT(hListview);
    
    
        //listview的列头句柄
        int headerhwnd = ::SendMessage(hListview, LVM_GETHEADER, 0, 0);
    
        //总行数
        int rows = ::SendMessage(hListview, LVM_GETITEMCOUNT, 0, 0);
        //列表列数
        int cols = ::SendMessage((HWND)headerhwnd, HDM_GETITEMCOUNT, 0, 0);
    
        DWORD ProcessID = NULL;
        DWORD ThreadID = GetWindowThreadProcessId(hListview, &ProcessID);
    
        //打开并插入进程
        HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, FALSE, ProcessID);
        //申请代码的内存区
        LPVOID pointer = (LVITEM*)VirtualAllocEx(hProcess, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE);
    
        bool result = false;
        for (int i = 0; i < rows; i++)
        {
            int j = 0;
            // for (int j = 0; j < cols; j++)
            {
                LVITEM vItem;
                vItem.mask = LVIF_TEXT;    //说明pszText是有效的
                vItem.iItem = i;        //行号
                vItem.iSubItem = j;        //列号
                vItem.cchTextMax = 512;    //所能存储的最大的文本为256字节
                LPWSTR pItem = NULL;
                //申请内存空间
                pItem = (LPWSTR)VirtualAllocEx(hProcess, NULL, 512, MEM_COMMIT, PAGE_READWRITE);
                vItem.pszText = pItem;
    
                WriteProcessMemory(hProcess, pointer, &vItem, sizeof(LVITEM), NULL);
                ::SendMessage(hListview, LVM_GETITEMW, (WPARAM)i, (LPARAM)pointer);
                char ItemBuf[512];
                memset(ItemBuf, 0, 512);
                ReadProcessMemory(hProcess, pItem, ItemBuf, 512, NULL);
    
                CString strItemText; //i行j列的文本值
                strItemText.Format(_T("%s"), ItemBuf);
                if (strItemText == stockCode)
                {
                    //选中行
                    vItem.state = LVIS_SELECTED | LVIS_FOCUSED | LVIS_ACTIVATING;
                    vItem.stateMask = LVIS_SELECTED;
                    WriteProcessMemory(hProcess, pointer, &vItem, sizeof(LVITEM), NULL);
                    SendMessage(hListview, LVM_SETITEMSTATE, (WPARAM)i, (LPARAM)pointer);
    
                    result = true;
                }
    
                //释放内存空间
                VirtualFreeEx(hProcess, pItem, 0, MEM_RELEASE);
            }
        }
    
        //释放内存空间
        VirtualFreeEx(hProcess, pointer, 0, MEM_RELEASE);//在其它进程中释放申请的虚拟内存空间,MEM_RELEASE方式很彻底,完全回收
        CloseHandle(hProcess);//关闭打开的进程对象
        return result;
    }
  • 记录一下php empty的坑

    php empty的坑:

    empty函数对于参数0也认为是TRUE

    比如:

    $a=0;

    那么 empty($a) 为真。

    真的坑。。

  • IronPython操作数据库

    IronPython操作数据库

    # -*- coding: utf-8 -*-
    import clr
    clr.AddReference('System.Data' )
    from System .Data import *
    
    conn = SqlClient.SqlConnection("server=42.96.190.81,2433;database=QQRobot;uid=sa;pwd=xinyang0822_xin;pooling=true;Enlist=true;connection lifetime=300;min pool size = 0;max pool size=512;packet size=1000")
    conn.Open()
    
    cmd = SqlClient.SqlCommand("select * from AIData where Id=1", conn)
    reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)
    
    while reader.Read():
        print reader[0]
    
    reader.Close()
    conn.Close()
  • C#使用Uri.EscapeDataString对URL参数进行编码

    System.Web.HttpUtility.UrlEncode

    都是对参数进行编码,要像下面这样写:

    string data = string.Format(@"{{""ptwebqq"":""{0}"",""clientid"":{1},""psessionid"":""{2}"",""status"":""online""}}", _PTWebQQ, ClientID, PSessionID);
    data = "r=" + Uri.EscapeDataString(data);

    而不要把r=也编码进去!!!

    血的教训,一晚上加一上午都浪费在这上面了!!!!

    而python的urllib.parse.urlencode传入的是字典,所以避免了这个坑。

  • Razor中判断是Debug模式还是Release模式

    Razor视图文件中判断是Debug模式还是Release模式

    @if (!HttpContext.Current.IsDebuggingEnabled)
    {
    }

    HttpContext.Current.IsDebuggingEnabled的值取决于web.config中的

    <compilation debug="true" targetFramework =" 4.5" />

  • .NET使用UDE.CSharp识别文件编码

    .NET中识别文件编码、识别字符集,有一个比较好用的包UDE.CSharp可以实现,这个包是Mozilla出品的,又叫Mozilla Universal Charset Detector。

    首先在nuget下载安装UED:

    使用样例如下:

    private void btnImport_Click(object sender, EventArgs e)
    {
        OpenFileDialog dlg = new OpenFileDialog();
        dlg.DefaultExt = ".txt";
        dlg.Filter = "txt文件|*.txt";
        if (dlg.ShowDialog() == System.Windows.Forms. DialogResult.OK)
        {
            _list.Clear();
            string filename = dlg.FileName;
    
            //使用Mozilla Universal Charset Detector侦测文件编码
            string charset = "UTF-8";
            using ( FileStream fs = File .OpenRead(filename))
            {
                Ude. CharsetDetector cdet = new Ude.CharsetDetector ();
                cdet.Feed(fs);
                cdet.DataEnd();
                if (cdet.Charset != null)
                {
                    charset = cdet.Charset;
                }
            }
    
            string[] lines = File.ReadAllLines(filename, Encoding.GetEncoding(charset));
    
            foreach ( var line in lines)
            {
                //去重
                if (_list.IndexOf(line) == -1)
                {
                    _list.Add(line);
                }
            }
        }
    }