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 ...
随机推荐
- # 20175329 2018-2019-3 《Java程序设计》第九周学习总结
20175329 2018-2019-3 <Java程序设计>第九周学习总结
- git@github.com: Permission denied (publickey).////remote: Permission to xxx/test.git denied to xxx.等权限问题
Error msg git@github.com: Permission denied (publickey) 或者: remote: Permission to xxx/test.git denie ...
- HTTP的一些基本概念
HTTP协议:HTTP(超文本传输协议)协议就是计算机在网络中进行通信所必须共同遵守的规则,它允许将超文本标记语言(HTML)文档从Web服务器传送到客户端的浏览器,我们目前使用的是HTTP/1.1 ...
- MySQL工作原理
Mysql是由SQL接口,解析器,优化器,缓存,存储引擎组成的. mysql原理图各个组件说明: 1. connectors 与其他编程语言中的sql 语句进行交互,如php.java等. 2. M ...
- Linux 安装多个版本JDK并设置默认版本
1 官网下载JDK版本 jdk-8u181-linux-x64.tar.gz 2 利用ssh工具上传安装包到Linux系统 传至:/usr/local 3 Linux用户安装的程序一般放在 /usr/ ...
- 内核调试打印dump_stack
https://blog.csdn.net/dragon101788/article/details/9419175 在函数中加入dump_stack函数 需要包含的头文件: #include < ...
- Java8新特性(一)_interface中的static方法和default方法
什么要单独写个Java8新特性,一个原因是我目前所在的公司用的是jdk8,并且框架中用了大量的Java8的新特性,如上篇文章写到的stream方法进行过滤map集合.stream方法就是接口Colle ...
- Vue.js 2.x笔记:指令(4)
1. 内置指令 指令是Vue.js 中一个重要的特性,主要提供了一种机制将数据的变化映射为DOM 行为. Vue.js 本身提供了大量的内置指令来进行对DOM 的操作,同时可以开发自定义指令. 2. ...
- VBS 备份文件
http://www.cnblogs.com/top5/archive/2009/11/17/1604767.html 参考上面的博客 ' =============== 局域网文件自动备份 VBS ...
- C语言博客作业05--指针
1.本章学习总结 1.1 思维导图 1.2 本章学习体会及代码量学习体会 1.2.1 学习体会 1.2.2 代码累计 2.PTA总分 2.1截图PTA中函数题目集的排名得分 2.2 我的总分: 3.P ...