2010-01-09 162 views
7

我想用Java生成一个.torrent文件,但我不想要一个大的API来执行任何类似于抓取跟踪器,种子等等的东西。这仅仅是一个生成元数据的客户端。存在哪些轻量级解决方我只生成单个.zip文件的.torrent。如何在Java中生成.torrent?

谢谢!

回答

22

我已经把这个自包含的Java代码放在一起来准备一个.torrent文件和一个文件。

通过调用createTorrent()传递.torrent文件的名称,共享文件的名称和跟踪器URL,创建.torrent文件。使用Java的MessageDigest类来散列文件。然后createTorrent()准备包含种子元数据的元信息词典。然后使用encode*()方法将该字典序列化为适当的明码格式并保存在.torrent文件中。

有关详细信息,请参阅BitTorrent spec

public class Torrent { 
    private static void encodeObject(Object o, OutputStream out) throws IOException { 
     if (o instanceof String) 
      encodeString((String)o, out); 
     else if (o instanceof Map) 
      encodeMap((Map)o, out); 
     else if (o instanceof byte[]) 
      encodeBytes((byte[])o, out); 
     else if (o instanceof Number) 
      encodeLong(((Number) o).longValue(), out); 
     else 
      throw new Error("Unencodable type"); 
    } 
    private static void encodeLong(long value, OutputStream out) throws IOException { 
     out.write('i'); 
     out.write(Long.toString(value).getBytes("US-ASCII")); 
     out.write('e'); 
    } 
    private static void encodeBytes(byte[] bytes, OutputStream out) throws IOException { 
     out.write(Integer.toString(bytes.length).getBytes("US-ASCII")); 
     out.write(':'); 
     out.write(bytes); 
    } 
    private static void encodeString(String str, OutputStream out) throws IOException { 
     encodeBytes(str.getBytes("UTF-8"), out); 
    } 
    private static void encodeMap(Map<String,Object> map, OutputStream out) throws IOException{ 
     // Sort the map. A generic encoder should sort by key bytes 
     SortedMap<String,Object> sortedMap = new TreeMap<String, Object>(map); 
     out.write('d'); 
     for (Entry<String, Object> e : sortedMap.entrySet()) { 
      encodeString(e.getKey(), out); 
      encodeObject(e.getValue(), out); 
     } 
     out.write('e'); 
    } 
    private static byte[] hashPieces(File file, int pieceLength) throws IOException { 
     MessageDigest sha1; 
     try { 
      sha1 = MessageDigest.getInstance("SHA"); 
     } catch (NoSuchAlgorithmException e) { 
      throw new Error("SHA1 not supported"); 
     } 
     InputStream in = new FileInputStream(file); 
     ByteArrayOutputStream pieces = new ByteArrayOutputStream(); 
     byte[] bytes = new byte[pieceLength]; 
     int pieceByteCount = 0, readCount = in.read(bytes, 0, pieceLength); 
     while (readCount != -1) { 
      pieceByteCount += readCount; 
      sha1.update(bytes, 0, readCount); 
      if (pieceByteCount == pieceLength) { 
       pieceByteCount = 0; 
       pieces.write(sha1.digest()); 
      } 
      readCount = in.read(bytes, 0, pieceLength-pieceByteCount); 
     } 
     in.close(); 
     if (pieceByteCount > 0) 
      pieces.write(sha1.digest()); 
     return pieces.toByteArray(); 
    } 
    public static void createTorrent(File file, File sharedFile, String announceURL) throws IOException { 
     final int pieceLength = 512*1024; 
     Map<String,Object> info = new HashMap<String,Object>(); 
     info.put("name", sharedFile.getName()); 
     info.put("length", sharedFile.length()); 
     info.put("piece length", pieceLength); 
     info.put("pieces", hashPieces(sharedFile, pieceLength)); 
     Map<String,Object> metainfo = new HashMap<String,Object>(); 
     metainfo.put("announce", announceURL); 
     metainfo.put("info", info); 
     OutputStream out = new FileOutputStream(file); 
     encodeMap(metainfo, out); 
     out.close(); 
    } 

    public static void main(String[] args) throws Exception { 
     createTorrent(new File("C:/x.torrent"), new File("C:/file"), "http://example.com/announce"); 
    } 
} 

代码编辑:让这一点更加紧凑,解决方法可视性,使用字符文字酌情使用instanceof Number。最近使用块I/O读取文件,因为我试图使用它作为真正的和字节I/O只是慢,

10

我会从Java Bittorrent API开始。这个罐子大约70Kb,但是你可以通过去掉创建种子所不需要的类来拆卸它。该SDK有一个样本ExampleCreateTorrent.java说明如何做到你所需要的。

您也可以看看它是如何在开源Java客户端(如Azureus)中实现的。