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 ...
随机推荐
- SQL 语法使用
SQL 语句 语句 语法 AND / OR SELECT column_name(s)FROM table_nameWHERE conditionAND|OR condition ALTER TABL ...
- centos7的内核区别
最近重新搭建环境准备测试一些东西,在网上随意下载了一个镜像,名字叫做:CentOS-7-i386-Everything-1810 下载完之后开始做实验安装软件的时候发现一直报错:[Errno 14] ...
- Django-CRM项目学习(八)-客户关系系统整体实现(待完成!)
注意点:利用stark组件与rbac组件实现客户关系系统 1.需求整理与确认 1.1 客户关系系统整体需求 a
- 记录一次无厘头的粗心失误——java后台报错:Unknown column 'xxx' in 'field list'
原因: sql文件马虎,直接用错了仓库.用的不是程序调用的仓库.而自己pojo和mapper还是采用Mybatis的逆向工程生成的.当时搞得很无厘头. 解决方案: sql用到程序指定的仓库就行啦. 总 ...
- vue 中 assets 和 static 的区别
Vue中的静态资源管理(src下的assets和static文件夹的区别)
- SSM项目整合Quartz
一.背景 SSM项目中要用到定时器,初期使用Timer,后来用spring 的schedule,都比较简单,所以功能比较单一而且他们不能动态的配置时间.后来就研究quartz,准备整合到项目中.Qua ...
- [转帖]Qemu 简述
Qemu 简述 记得KVM 就是 底层用的qemu https://www.cnblogs.com/bakari/p/7858029.html 本文首发于我的公众号 Linux云计算网络(id: cl ...
- Virtual DOM 系列三:Diff算法
DOM操作是昂贵的,为了减少DOM操作,才有了Virtual DOM.而Virtual DOM的关键就是通过对比新旧vnode,找出差异部分来更新节点.对比的关键算法就是Diff算法. 历史由来: d ...
- 在vue 里使用腾讯ditu
https://www.cnblogs.com/mrer/p/7144705.html
- Salesforce Bulk API 基于.Net平台下的实施
在最近的salesforce实施项目中应用到Bulk API来做数据接口.顺便把实际应用的例子写下来.希望对做salesforce接口的朋友有借鉴作用. 一 参考网络牛人写好的Demo. 下载地址:h ...