随笔 - 165, 文章 - 0, 评论 - 18, 阅读 - 22万
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

【转】C#读取QQ纯真IP数据库中的数据

Posted on   火冰·瓶  阅读(685)  评论(1编辑  收藏  举报

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
public class CZ_INDEX_INFO
{
    public UInt32 IpSet;
    public UInt32 IpEnd;
    public UInt32 Offset;
 
    public CZ_INDEX_INFO()
    {
        IpSet = 0;
        IpEnd = 0;
        Offset = 0;
    }
}
//读取纯真IP数据库类
public class PHCZIP
{
    protected bool bFilePathInitialized;
    protected string FilePath;
    protected FileStream FileStrm;
    protected UInt32 Index_Set;
    protected UInt32 Index_End;
    protected UInt32 Index_Count;
    protected UInt32 Search_Index_Set;
    protected UInt32 Search_Index_End;
    protected CZ_INDEX_INFO Search_Set;
    protected CZ_INDEX_INFO Search_Mid;
    protected CZ_INDEX_INFO Search_End;
 
    public PHCZIP()
    {
        bFilePathInitialized = false;
    }
 
    public PHCZIP(string dbFilePath)
    {
        bFilePathInitialized = false;
        SetDbFilePath(dbFilePath);
    }
 
    //使用二分法查找索引区,初始化查找区间
    public void Initialize()
    {
        Search_Index_Set = 0;
        Search_Index_End = Index_Count - 1;
    }
 
    //关闭文件
    public void Dispose()
    {
        if (bFilePathInitialized)
        {
            bFilePathInitialized = false;
            FileStrm.Close();
            //FileStrm.Dispose();
        }
 
    }
 
 
    public bool SetDbFilePath(string dbFilePath)
    {
        if (dbFilePath == "")
        {
            return false;
        }
 
        try
        {
            FileStrm = new FileStream(dbFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
        }
        catch
        {
            return false;
        }
        //检查文件长度
        if (FileStrm.Length < 8)
        {
            FileStrm.Close();
            //FileStrm.Dispose();
            return false;
        }
        //得到第一条索引的绝对偏移和最后一条索引的绝对偏移
        FileStrm.Seek(0, SeekOrigin.Begin);
        Index_Set = GetUInt32();
        Index_End = GetUInt32();
 
        //得到总索引条数
        Index_Count = (Index_End - Index_Set) / 7 + 1;
        bFilePathInitialized = true;
 
        return true;
 
    }
 
    public string GetAddressWithIP(string IPValue)
    {
        if (!bFilePathInitialized)
            return "";
 
        Initialize();
 
        UInt32 ip = IPToUInt32(IPValue);
 
        while (true)
        {
 
            //首先初始化本轮查找的区间
 
            //区间头
            Search_Set = IndexInfoAtPos(Search_Index_Set);
            //区间尾
            Search_End = IndexInfoAtPos(Search_Index_End);
 
            //判断IP是否在区间头内
            if (ip >= Search_Set.IpSet && ip <= Search_Set.IpEnd)
                return ReadAddressInfoAtOffset(Search_Set.Offset);
 
 
            //判断IP是否在区间尾内
            if (ip >= Search_End.IpSet && ip <= Search_End.IpEnd)
                return ReadAddressInfoAtOffset(Search_End.Offset);
 
            //计算出区间中点
            Search_Mid = IndexInfoAtPos((Search_Index_End + Search_Index_Set) / 2);
 
            //判断IP是否在中点
            if (ip >= Search_Mid.IpSet && ip <= Search_Mid.IpEnd)
                return ReadAddressInfoAtOffset(Search_Mid.Offset);
 
            //本轮没有找到,准备下一轮
            if (ip < Search_Mid.IpSet)
                //IP比区间中点要小,将区间尾设为现在的中点,将区间缩小1倍。
                Search_Index_End = (Search_Index_End + Search_Index_Set) / 2;
            else
                //IP比区间中点要大,将区间头设为现在的中点,将区间缩小1倍。
                Search_Index_Set = (Search_Index_End + Search_Index_Set) / 2;
        }
    }
 
    private string ReadAddressInfoAtOffset(UInt32 Offset)
    {
        string country = "";
        string area = "";
        UInt32 country_Offset = 0;
        byte Tag = 0;
        //跳过4字节,因这4个字节是该索引的IP区间上限。
        FileStrm.Seek(Offset + 4, SeekOrigin.Begin);
 
        //读取一个字节,得到描述国家信息的“寻址方式”
        Tag = GetTag();
 
        if (Tag == 0x01)
        {
 
            //模式0x01,表示接下来的3个字节是表示偏移位置
            FileStrm.Seek(GetOffset(), SeekOrigin.Begin);
 
            //继续检查“寻址方式”
            Tag = GetTag();
            if (Tag == 0x02)
            {
                //模式0x02,表示接下来的3个字节代表国家信息的偏移位置
                //先将这个偏移位置保存起来,因为我们要读取它后面的地区信息。
                country_Offset = GetOffset();
                //读取地区信息(注:按照Luma的说明,好像没有这么多种可能性,但在测试过程中好像有些情况没有考虑到,
                //所以写了个ReadArea()来读取。
                area = ReadArea();
                //读取国家信息
                FileStrm.Seek(country_Offset, SeekOrigin.Begin);
                country = ReadString();
            }
            else
            {
                //这种模式说明接下来就是保存的国家和地区信息了,以'\0'代表结束。
                FileStrm.Seek(-1, SeekOrigin.Current);
                country = ReadString();
                area = ReadArea();
 
            }
        }
        else if (Tag == 0x02)
        {
            //模式0x02,说明国家信息是一个偏移位置
            country_Offset = GetOffset();
            //先读取地区信息
            area = ReadArea();
            //读取国家信息
            FileStrm.Seek(country_Offset, SeekOrigin.Begin);
            country = ReadString();
        }
        else
        {
            //这种模式最简单了,直接读取国家和地区就OK了
            FileStrm.Seek(-1, SeekOrigin.Current);
            country = ReadString();
            area = ReadArea();
 
        }
        string Address = country + " " + area;
        return Address;
 
    }
 
    private UInt32 GetOffset()
    {
        byte[] TempByte4 = new byte[4];
        TempByte4[0] = (byte)FileStrm.ReadByte();
        TempByte4[1] = (byte)FileStrm.ReadByte();
        TempByte4[2] = (byte)FileStrm.ReadByte();
        TempByte4[3] = 0;
        return BitConverter.ToUInt32(TempByte4, 0);
    }
 
    protected string ReadArea()
    {
        byte Tag = GetTag();
 
        if (Tag == 0x01 || Tag == 0x02)
        {
            FileStrm.Seek(GetOffset(), SeekOrigin.Begin);
            return ReadString();
        }
        else
        {
            FileStrm.Seek(-1, SeekOrigin.Current);
            return ReadString();
        }
    }
 
    protected string ReadString()
    {
        UInt32 Offset = 0;
        byte[] TempByteArray = new byte[256];
        TempByteArray[Offset] = (byte)FileStrm.ReadByte();
        while (TempByteArray[Offset] != 0x00)
        {
            Offset += 1;
            TempByteArray[Offset] = (byte)FileStrm.ReadByte();
        }
        return System.Text.Encoding.Default.GetString(TempByteArray).TrimEnd('\0');
    }
 
    protected byte GetTag()
    {
        return (byte)FileStrm.ReadByte();
    }
 
    protected CZ_INDEX_INFO IndexInfoAtPos(UInt32 Index_Pos)
    {
        CZ_INDEX_INFO Index_Info = new CZ_INDEX_INFO();
        //根据索引编号计算出在文件中在偏移位置
        FileStrm.Seek(Index_Set + 7 * Index_Pos, SeekOrigin.Begin);
        Index_Info.IpSet = GetUInt32();
        Index_Info.Offset = GetOffset();
        FileStrm.Seek(Index_Info.Offset, SeekOrigin.Begin);
        Index_Info.IpEnd = GetUInt32();
 
        return Index_Info;
    }
 
    public UInt32 IPToUInt32(string IpValue)
    {
        string[] IpByte = IpValue.Split('.');
        Int32 nUpperBound = IpByte.GetUpperBound(0);
        if (nUpperBound != 3)
        {
            IpByte = new string[4];
            for (Int32 i = 1; i <= 3 - nUpperBound; i++)
                IpByte[nUpperBound + i] = "0";
        }
 
        byte[] TempByte4 = new byte[4];
        for (Int32 i = 0; i <= 3; i++)
        {
            //'如果是.Net 2.0可以支持TryParse。
            //'If Not (Byte.TryParse(IpByte(i), TempByte4(3 - i))) Then
            //'      TempByte4(3 - i) = &H0
            //'End If
            if (IsNumeric(IpByte[i]))
                TempByte4[3 - i] = (byte)(Convert.ToInt32(IpByte[i]) & 0xff);
        }
 
        return BitConverter.ToUInt32(TempByte4, 0);
    }
 
    protected bool IsNumeric(string str)
    {
        if (str != null && System.Text.RegularExpressions.Regex.IsMatch(str, @"^-?\d+$"))
            return true;
        else
            return false;
    }
 
    protected UInt32 GetUInt32()
    {
        byte[] TempByte4 = new byte[4];
        FileStrm.Read(TempByte4, 0, 4);
        return BitConverter.ToUInt32(TempByte4, 0);
    }
}

测试用时:

1
2
3
4
string path = Server.MapPath("QQWry.Dat");
PHCZIP zip = new PHCZIP(path);
 
string address = zip.GetAddressWithIP("125.70.76.85");
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示