📄 encoderbencoding.java
字号:
package com.sinpool.rivercrescent;
import java.io.*;
import java.util.*;
import javax.swing.*;
import java.security.*;
import com.sinpool.rivercrescent.interfaces.*;
/**这个类是为了编码Bencoding码的,
*Bencoding码是python(一种面向对象语言)的编码形式,
*因为BitTorrent之父Bram Cohen,
*使用python实现了第一个BT软件,
*所以BT协议中的数据结构,
*都遵循python的规则.
*这也是Bram Cohen所倡导的.
*
*创建时间:2005.1.19
*@author Sinpool.
*@version 1.0
*
**/
public class EncoderBencoding implements Bencoding{
private File inFileName = null;
private File outFileName = null;
private FileInputStream fis = null;
private BufferedInputStream in = null;
private FileOutputStream fos = null;
private BufferedOutputStream bos = null;
private PrintWriter out = null;
private StringBuffer head = new StringBuffer();
private int total = 0;
private byte[] fileData;
private int pl;
private boolean single = true; //标示编码的文件是否为单文件
private String root = null, outFile = null;
public EncoderBencoding(){
this.setPL(this.PIECE_LENGTH256);
this.setSingle(false);
/*要作一个自动分块的方法
*
*
*
*
*
*
*/
}
/**用来打开输入文件
*/
private boolean openInFile() throws IOException{
//现实文件选择框
JFileChooser jfc = new JFileChooser();
int state = jfc.showOpenDialog(null);
if (state == JFileChooser.APPROVE_OPTION ) inFileName = jfc.getSelectedFile();
else return false;
total = (int)inFileName.length();
fileData = new byte[total];
fis = new FileInputStream(inFileName);
in = new BufferedInputStream(fis);
return true;
}
/**用来打开输出文件
*/
private void openOutFile() throws IOException{
String tempFile = "riverfile\\" + inFileName.getName() + ".river";
outFileName = new File(tempFile);
fos = new FileOutputStream(outFileName);
bos = new BufferedOutputStream(fos);
out = new PrintWriter(fos);
}
//返回每个键名的字符串长度
private String keyCount(String keyName){
String result = new Integer(keyName.getBytes().length).toString();
result += ":";
return result;
}
//返回整数的字符串
private String getIntString(int keyValue){
return new Integer(keyValue).toString();
}
//返回当前时间,Unix标准时间,
//从1970年1月1日 00:00:00 到目前的描秒数
private String getCurrentTime(){
Date date = new Date();
long time = date.getTime();
time /= 1000;
String result = new Long(time).toString();
return result;
}
//计算单文件的sha1 hash
private void parseSHA1_single() throws IOException{
Status status = new Status(total);
MessageDigest sha = null;
byte[] hash = new byte[20];
fileData = new byte[pl];
int kuai = (total%pl == 0)?total/pl:(total/pl+1);
out.print((new Integer(kuai*20).toString()) + ":");
out.flush();
try{
sha = MessageDigest.getInstance("sha-1");
}catch (NoSuchAlgorithmException e) {System.out.println("Error! 无效编码NoSuchAlgorithm!");return;}
for (int i=0;i<kuai;i++){
in.read(fileData);
sha.update(fileData);
hash = sha.digest();
bos.write(hash);
status.setValue((i+1)*pl);
}
status.dispose();
bos.flush();
out.write("ee");
out.flush();
out.close();
bos.close();
fos.close();
in.close();
fis.close();
}
//计算多文件的sha1 hash
private void parseSHA1_multiple() throws IOException{
long kuai = 0;
String subPath = null,path = null,temp = null;
MessageDigest sha = null;
byte[] hash = new byte[20];
Vector files = foundFiles();
if (files == null ) {
System.out.println("取消了选择文件的操作。");
return;
}
File f =null;
int[] kuais = new int[files.size()];
out.print(head.toString());
out.flush();
pathAddToFile(files);
out.print("e4:name");
out.print(keyCount(outFile) + outFile);
out.print(keyCount(piece_length) + piece_length);
out.print("i" + getIntString(pl) + "e");
out.print("6:pieces");
for(int i=0;i<files.size();i++){
subPath = (String)files.get(i);
path = root + subPath;
f = new File(path);
total = (int)f.length();
kuais[i] = (total%pl == 0)?total/pl:(total/pl+1);
kuai += kuais[i];
}
out.print((new Long(kuai*20).toString()) + ":");
out.flush();
System.out.println("开始对文件夹中的每个文件编码...");
Status status = new Status(kuais[0]);
fileData = new byte[pl];
try{
sha = MessageDigest.getInstance("sha-1");
}catch (NoSuchAlgorithmException e) {System.out.println("Error! 无效编码NoSuchAlgorithm!");return;}
for(int j=0;j<files.size();j++){
inFileName = new File(root + (String)files.get(j));
fis = new FileInputStream(inFileName);
in = new BufferedInputStream(fis);
status.setMax(kuais[j]);
for (int i=0;i<kuais[j];i++){
in.read(fileData);
sha.update(fileData);
hash = sha.digest();
bos.write(hash);
bos.flush();
status.setValue(i+1);
}
}
status.dispose();
out.write("e");
out.flush();
out.close();
bos.close();
fos.close();
in.close();
fis.close();
}
//此方法用于将补充元信息文件
private void pathAddToFile(Vector s){
File f = null;
String subPath = null,path = null,temp = null;
for(int i=0;i<s.size();i++){
subPath = (String)s.get(i);
path = root + subPath;
f = new File(path);
out.print("d6:" + "length");
out.print("i" + getIntString((int)f.length()) + "e");
out.print("4:" + "pathl");
StringTokenizer st = new StringTokenizer(subPath,"\\");
while (st.hasMoreTokens()) {
temp = st.nextToken();
out.print(keyCount(temp) + temp);
}
out.print("ee");
out.flush();
}
}
//用于查找指定目录中的文件
private Vector foundFiles() throws IOException{
File[] temp = null;
Vector files = new Vector(5);
Stack directoreis = new Stack();
File current;
int String_index = 0;
JFileChooser jfc = new JFileChooser();
jfc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
//选择要发布的文件夹
int state = 0 ,response = 10;
while (response != 0){
state = jfc.showDialog(null,"Select");
inFileName = jfc.getSelectedFile();
if ( state != JFileChooser.APPROVE_OPTION ) return null;
response = JOptionPane.showConfirmDialog(null,"是否选择:\""+inFileName.getPath()+"\"目录?",
"确认!",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE);
}
//处理选择的文件夹
root = inFileName.getPath();
outFile = inFileName.getName();
String_index = root.length();
System.out.println("正在分析文件夹...");
current = new File(root);
temp = current.listFiles();
while ( true ){
for (int i=0;i<temp.length;i++){
if (temp[i].isDirectory()) directoreis.push(temp[i]);
else {
files.addElement(temp[i].getAbsolutePath().substring(String_index));
}
}
if (directoreis.empty()) break;
temp = ((File)directoreis.pop()).listFiles();
}
String tempFile = "riverfile\\" + outFile + ".river";
outFileName = new File(tempFile);
fos = new FileOutputStream(outFileName);
bos = new BufferedOutputStream(fos);
out = new PrintWriter(fos);
return files;
}
public void setPL(int i){
this.pl = i;
}
public void setSingle(boolean b){
this.single = b;
}
/**具体的编码工作
*不返回任何数据
*/
public void encoderBencoding(){
head.append("d");
head.append(keyCount(creation_date) + creation_date);
head.append("i" + getCurrentTime() + "e");
head.append(keyCount(created_by) + created_by);
head.append(keyCount("Sinpool") + "Sinpool");
new File("riverfile").mkdir(); //创建保存元文件的文件夹,以免用户误删除。
//如果是单文件
if ( single ) {
head.append(keyCount(type) + type);
head.append(keyCount("single") + "single");
try{
if ( openInFile() ) openOutFile();
else {
System.out.println("没有选择要发布的文件,放弃了操作!");
return;
}
}catch (IOException ioe) {
System.out.println("选择要发布的文件时出错!");
return;
}
head.append(keyCount(info) + info + "d");
head.append(keyCount(length) + length);
head.append("i" + getIntString(total) + "e");
head.append(keyCount(name) + name);
head.append(keyCount(inFileName.getName()) + inFileName.getName());
head.append(keyCount(piece_length) + piece_length);
head.append("i" + getIntString(pl) +"e");
head.append(keyCount(pieces) + pieces);
out.print(head.toString());
out.flush();
try{
this.parseSHA1_single();
}catch (IOException e) {System.out.println("转换sha1 hash时出错!");return;}
}
//如果是多文件
else {
head.append(keyCount(type) + type);
head.append(keyCount("multiple") + "multiple");
head.append(keyCount(info) + info + "d");
head.append(keyCount(files) + files + "l");
try{
this.parseSHA1_multiple();
}catch (IOException e) {System.out.println("转换sha1 hash时出错!");return;}
}
}
//获得元文件文件名
public String getRiverscentFileName(){
return outFileName.getName();
}
//获得共享文件绝对路径名,单文件时使用。
public String getShareFileAbsoluteFileName(){
return inFileName.getAbsolutePath();
}
//获得共享文件的路径,多文件时使用。
public String getShareFilePath(){
return root;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -