C# 解析torrent文件
基础知识:
torrent文件信息存储格式:
bencoding是一种以简洁格式指定和组织数据的方法。支持下列类型:字节串、整数、列表和字典。
1 字符串存储格式: <字符串的长度>:<字符串的内容>
例如: 4:abcd 表示abcd, 2:ab 表示ab
2 数字的存储格式: i<整数>e
例如: i32e 表示整数32, i1024e 表示整数1024
3 列表的存储格式: l<子元素>e 其中:子元素可以是字符串,整数,列表和字典,或者是它们的组合体
例如: l4:asdf4:qwere 表示 [ "asdf", "qwer" ]
4 字典的存储格式: d<<key><value><key><value><key><value>...<key><value>>e
其中:key只能是字符串类型,value则可以是字符串,整数,列表和字典,或者是它们的组合体,key和value必须是成对出现的
例如: d3:cow3:moo4:spam4:eggse 表示 { "cow" => "moo", "spam" => "eggs" }
d4:spaml1:a1:bee 表示 { "spam" => [ "a", "b" ] }
d9:publisher3:bob4:spaml1:a1:be5:counti80ee 表示 { "publisher" => "bob", "spam" => [ "a", "b" ], "count" => 80 }
代码:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using NPOI.OpenXmlFormats.Spreadsheet;
using Newtonsoft.Json; namespace ConsoleApp
{
/// <summary>
/// Summary description for Class1.-change wdq
/// </summary>
public class Class1
{
static void Main(string[] args)
{
if (args.Length != )
{
Console.WriteLine("请指定torrent文件");
return;
}
string filename = args[];
var data = Torrent.DecodeFile(filename);
//Console.WriteLine(JsonConvert.SerializeObject(data, Newtonsoft.Json.Formatting.Indented));
ShowData(data);
} private static void ShowData(ItemBase data)
{
if (data.ItemType == ItemType.Dictionary)
{
foreach (var kv in (data as DictionaryItem).DictionaryData)
{
switch (kv.Value.ItemType)
{
case ItemType.Dictionary:
Console.WriteLine(kv.Key + ":");
ShowData(kv.Value);
break;
case ItemType.List:
Console.WriteLine(kv.Key + ":");
ShowData(kv.Value);
break;
case ItemType.String:
if (kv.Key == "pieces")
{
break;
}
Console.WriteLine(kv.Key + "=" + (kv.Value as StringItem).StringData);
break;
case ItemType.Number:
Console.WriteLine(kv.Key + "=" + (kv.Value as NumberItem).NumberData);
break;
}
}
}
if (data.ItemType == ItemType.List)
{
foreach (var i in (data as ListItem).ListData)
{
switch (i.ItemType)
{
case ItemType.Dictionary:
case ItemType.List:
ShowData(i);
break;
case ItemType.String:
Console.WriteLine((i as StringItem).StringData);
break;
case ItemType.Number:
Console.WriteLine((i as NumberItem).NumberData);
break;
}
}
}
}
} public class Torrent
{
public static ItemBase DecodeFile(string filename)
{
using (var fs = new FileStream(filename, FileMode.Open))
{
using (BinaryReader br = new BinaryReader(fs))
{
return DecodeData(br);
}
}
} private static ItemBase DecodeData(BinaryReader br, Stack<bool> st = null)
{
var flag = br.PeekChar();
List<byte> ls = new List<byte>();
byte b = ;
switch (flag)
{
case 'e':
br.ReadByte();
return null;
case 'l'://列表
br.ReadByte();
var itemLs = new ListItem();
ItemBase i = null;
if (st == null)
{
st = new Stack<bool>();
}
st.Push(true);
do
{
i = DecodeData(br, new Stack<bool>());
if (i != null)
{
itemLs.ListData.Add(i);
}
else
{
st.Pop();
}
} while (st.Count != && br.BaseStream.Position != br.BaseStream.Length); return itemLs;
case 'd'://字典
br.ReadByte();
var itemDic = new DictionaryItem();
var key = DecodeData(br);
while (key != null && br.BaseStream.Position != br.BaseStream.Length)
{
var val = DecodeData(br);
itemDic.DictionaryData[(key as StringItem).StringData] = val;
key = DecodeData(br);
} return itemDic;
case 'i'://数字
br.ReadByte();
b = br.ReadByte();
while (b != 'e')
{
ls.Add(b);
b = br.ReadByte();
}
return new NumberItem(long.Parse(Encoding.UTF8.GetString(ls.ToArray()))) { RawBytes = ls.ToArray() };
default://字符串
b = br.ReadByte();
while (b != ':')
{
ls.Add(b);
b = br.ReadByte();
}
var len = int.Parse(Encoding.UTF8.GetString(ls.ToArray()));
var bufStr = br.ReadBytes(len);
var data = Encoding.UTF8.GetString(bufStr);
return new StringItem(data) { RawBytes = bufStr };
}
}
} public class ItemBase
{
[JsonIgnore]
public ItemType ItemType { get; set; }
[JsonIgnore]
public byte[] RawBytes { get; set; }
} public class StringItem : ItemBase
{
public StringItem(string data)
{
StringData = data;
ItemType = ItemType.String;
}
public string StringData { get; set; }
}
public class NumberItem : ItemBase
{
public NumberItem(long num)
{
NumberData = num;
ItemType = ItemType.Number;
}
public long NumberData { get; set; }
} public class ListItem : ItemBase
{
public ListItem()
{
ItemType = ItemType.List;
}
public List<ItemBase> ListData { get; set; } = new List<ItemBase>();
} public class DictionaryItem : ItemBase
{
public DictionaryItem()
{
ItemType = ItemType.Dictionary;
}
public Dictionary<string, ItemBase> DictionaryData { get; set; } = new Dictionary<string, ItemBase>();
} public enum ItemType
{
String, Number, List, Dictionary
}
}
Github地址:https://github.com/a14907/AConsoleAppForFun.git
效果:
C# 解析torrent文件的更多相关文章
- Torrent文件的解析与转换
Torrent简介 BitTorrent协议的种子文件(英语:Torrent file)可以保存一组文件的元数据.这种格式的文件被BitTorrent协议所定义.扩展名一般为".torren ...
- Android 解析XML文件和生成XML文件
解析XML文件 public static void initXML(Context context) { //can't create in /data/media/0 because permis ...
- CSharpGL(9)解析OBJ文件并用CSharpGL渲染
CSharpGL(9)解析OBJ文件并用CSharpGL渲染 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo ...
- Jsoup系列学习(2)-解析html文件
解析html文件 1.当我们通过发送http请求时,有时候返回结果是一个html格式字符串,你需要从一个网站获取和解析一个HTML文档,并查找其中的相关数据.你可以使用下面解决方法: 使用 Jsoup ...
- JAVA使用SAX解析XML文件
在我的另一篇文章(http://www.cnblogs.com/anivia/p/5849712.html)中,通过一个例子介绍了使用DOM来解析XML文件,那么本篇文章通过相同的XML文件介绍如何使 ...
- JAVA中使用DOM解析XML文件
XML是一种方便快捷高效的数据保存传输的格式,在JSON广泛使用之前,XML是服务器和客户端之间数据传输的主要方式.因此,需要使用各种方式,解析服务器传送过来的信息,以供使用者查看. JAVA作为一种 ...
- CSharpGL(5)解析3DS文件并用CSharpGL渲染
CSharpGL(5)解析3DS文件并用CSharpGL渲染 我曾经写过一个简单的*.3ds文件的解析器,但是只能解析最基本的顶点.索引信息,且此解析器是仿照别人的C++代码改写的,设计的也不好,不方 ...
- php解析.csv文件
public function actionImport() { //post请求过来的 $fileName = $_FILES['file']['name']; $fileTmpName = $_F ...
- java中采用dom4j解析xml文件
一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...
随机推荐
- 三十六、fetch
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API
- icpc南宁站赛后总结
11月24号,我们经过26个小时的火车来到了广西南宁,一场漫长的过程. 24号晚到达南宁,做地铁到达学校,找到住的地方,南宁的天真是让人无奈. 25号,上午去广西大学体育馆报道,然后回去好好整理了一下 ...
- WordPress博客搭建与问题总结
一.WordPress博客搭建 1.安装Apache web服务器 yum install -y httpd systemctl restart httpd systemctl enable ht ...
- C++通用WMI接口实现获取Windows操作系统内核版本号
作为一名Windows开发者,能熟练掌握WMI技术,在开发Windows应用程序的时候往往能够事半功倍.今天来给大家分享一个使用WMI来获取Windows操作系统内核版本号的例子. 首先我们打开WMI ...
- Python——pyqt5——智能提示(lineEdit/conmbobox)
一.文本框智能补全 completer = QtWidgets.QCompleter(data) completer.setCompletionMode(QtWidgets.QCompleter.Po ...
- html 通用导航 a链接跳转时给当前导航添加选中颜色
学习前端的同学或许会遇到这个问题 做一个基本的小站有几个导航的,如下图 无论有几个页面,这里的导航的样式都是一样,唯一不同的就是进入哪个页面时当前有个选中的样式 一般这样通用的导航在开发的时候都会封装 ...
- 台达PLC实现远程下载程序
台达PLC实现远程下载程序 日期:2019-04-27 时间 08:33:57 让物联变得更简单 18-09-2411:25 明明在公司调试没问题的设备一到 ...
- bugku web web5
JSPFUCK??????答案格式CTF{**} http://123.206.87.240:8002/web5/ 字母大写 jspfuck这不是骂人吗,怎么回事啊? ·点进去看见有一个可以输入的框, ...
- vim主题颜色
1.VIM主题 查看Vim示例当前的颜色主题 打开一个Vim窗口,输入命令:color或:colorscheme后回车查看当前的颜色主题. Vim实例中设置颜色主题 输入命令"colorsc ...
- 「洛谷5300」「GXOI/GZOI2019」与或和【单调栈+二进制转化】
题目链接 [洛谷传送门] 题解 按位处理. 把每一位对应的图都处理出来 然后单调栈处理一下就好了. \(and\)操作处理全\(1\). \(or\)操作处理全\(0\). 代码 #include & ...