基础知识:

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文件的更多相关文章

  1. Torrent文件的解析与转换

    Torrent简介 BitTorrent协议的种子文件(英语:Torrent file)可以保存一组文件的元数据.这种格式的文件被BitTorrent协议所定义.扩展名一般为".torren ...

  2. Android 解析XML文件和生成XML文件

    解析XML文件 public static void initXML(Context context) { //can't create in /data/media/0 because permis ...

  3. CSharpGL(9)解析OBJ文件并用CSharpGL渲染

    CSharpGL(9)解析OBJ文件并用CSharpGL渲染 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo ...

  4. Jsoup系列学习(2)-解析html文件

    解析html文件 1.当我们通过发送http请求时,有时候返回结果是一个html格式字符串,你需要从一个网站获取和解析一个HTML文档,并查找其中的相关数据.你可以使用下面解决方法: 使用 Jsoup ...

  5. JAVA使用SAX解析XML文件

    在我的另一篇文章(http://www.cnblogs.com/anivia/p/5849712.html)中,通过一个例子介绍了使用DOM来解析XML文件,那么本篇文章通过相同的XML文件介绍如何使 ...

  6. JAVA中使用DOM解析XML文件

    XML是一种方便快捷高效的数据保存传输的格式,在JSON广泛使用之前,XML是服务器和客户端之间数据传输的主要方式.因此,需要使用各种方式,解析服务器传送过来的信息,以供使用者查看. JAVA作为一种 ...

  7. CSharpGL(5)解析3DS文件并用CSharpGL渲染

    CSharpGL(5)解析3DS文件并用CSharpGL渲染 我曾经写过一个简单的*.3ds文件的解析器,但是只能解析最基本的顶点.索引信息,且此解析器是仿照别人的C++代码改写的,设计的也不好,不方 ...

  8. php解析.csv文件

    public function actionImport() { //post请求过来的 $fileName = $_FILES['file']['name']; $fileTmpName = $_F ...

  9. java中采用dom4j解析xml文件

    一.前言 在最近的开发中用到了dom4j来解析xml文件,以前听说过来解析xml文件的几种标准方式:但是从来的没有应用过来,所以可以在google中搜索dmo4j解析xml文件的方式,学习一下dom4 ...

随机推荐

  1. RecyclerView的Item的单击事件

    RecyclerView 的每个Item的点击事件并没有像ListView一样封装在组件中,需要Item的单击事件时就需要自己去实现,在Adapter中为RecyclerView添加单击事件参考如下: ...

  2. [SNOI2017]炸弹

    嘟嘟嘟 这题有一些别的瞎搞神奇做法,而且复杂度似乎更优,不过我为了练线段树,就乖乖的官方正解了. 做法就是线段树优化建图+强连通分量缩点+DAGdp. 如果一个炸弹\(i\)能引爆另一个炸弹\(j\) ...

  3. libgdx学习记录2——文字显示BitmapFont

    libgdx对中文支持不是太好,主要通过Hireo和ttf字库两种方式实现.本文简单介绍最基本的bitmapfont的用法. 代码如下: package com.fxb.newtest; import ...

  4. BAT面试题:使用数组实现一个简单的阻塞队列

    这道题是我亲身经历的一道大厂面试题,非常值得分享! 这道题可以分为两个步骤进行编码解答,第一步是基于数组实现一个队列,第二步是实现线程阻塞. 如果是基于数组实现栈的数据结构,那么我们只需要一个指针进行 ...

  5. vue中怎么全局引入sass文件

    1.添加依赖 npm install sass-resources-loader --save-dev 2.修改build/utils.js scss: generateLoaders('sass') ...

  6. 浅析Java数据类型

    前言: 该系列会辅以MindMap进行说明. 下面会贴两张我不同时期画的Java数据类型的思维导图,本篇主要侧重于Java的8种基本类型 MindMap-1 这张MindMap主要是根据 菜鸟教程+参 ...

  7. MCMC算法解析

    MCMC算法的核心思想是我们已知一个概率密度函数,需要从这个概率分布中采样,来分析这个分布的一些统计特性,然而这个这个函数非常之复杂,怎么去采样?这时,就可以借助MCMC的思想. 它与变分自编码不同在 ...

  8. DNS预解析prefetch

    前面的话 本文将详细介绍DNS预解析prefetch的主要内容 概述 DNS(Domain Name System, 域名系统),是域名和IP地址相互映射的一个分布式数据库.DNS 查询就是将域名转换 ...

  9. 《玩转spring全家桶》学习笔记-------------丁雪丰

    一.spring 课程介绍 1.初识spring 2.数据操作 3.web开发 4.spring boot 5.spring cloud 二.初识spring Spring Boot.Spring C ...

  10. 百度编辑器前后端二开图片上传Js Thinkphp tp5 ueditor

    百度编辑器图片上传Jsueditor.all.min.js 下载链接 链接:https://pan.baidu.com/s/1VNgw9ELgRRHKeCQheFkQTw 提取码:fnfi 使用方法: ...