目前用java在做一个「多线程下载工具」,想要实现类似迅雷那样自动识别url所指资源的文件名和后缀。尝试以下办法:
HttpURLConnection http = (HttpURLConnection)url.openConnection();
http.connect();String field=http.getHeaderField("Content-Disposition");
String tmpStr1=field.substring(field.indexOf("filename")+10, field.length()-1); //获取filename="xxx"中的xxx
String tmpStr2=new String(tmpStr1.getBytes("ISO-8859-1"), "GB2312"); //编码转换,正确识别中文
System.out.println(tmpStr2);
遇到两个问题:
1、String tmpStr2=new String(tmpStr1.getBytes("ISO-8859-1"), "GB2312");
对某些http响应信息里的中文字符,依然会出现乱码。http的默认编码不是“ISO-8859-1”吗?还是说有别的问题?2、这段代码只能获取某些url的文件名和后缀,对很多url无效。我检查了一下这些url的http响应信息,不含Content-Disposition字段。这是为什么?请高手不吝赐教,有没有一种强健的方式能够获取url所指资源的真实文件名和后缀。非常感谢。

解决方案 »

  1.   

    public class MultiThreadGetFile extends Thread
    {
      long startPos=0,endPos=0;
      String currentFileThreadName;//要带上完整的路径
      String urlFile;//网络文件地址
      String urlFileName;//网络文件名
      String localFileAddress;//下载文件要存放的地址
      int threadNum;//要同时下载的线程数
      long[] eachThreadLength;//每个线程要下功的文件分块的大小
      long urlFileLength;//网络文件的大小
      URL url;
      HttpURLConnection httpURLConnection;
      public static boolean[] checkList;//检测线程
      public MultiThreadGetFile(String urlFile,int threadNum,String localFileAddress)
      {
        this.urlFile=urlFile;
        this.threadNum=threadNum;//要同时下载的线程数
        this.localFileAddress=localFileAddress;
        
      }
      private void init_getEachThreadLength()//确定每个线程文件最终要写的文件在大小
      {
        long l;
        l=urlFileLength/threadNum;
        for(int i=0;i<threadNum;i++)
        {
          if(i==threadNum-1)//如果是分配最后一个线程了
          {
            eachThreadLength[i]=urlFileLength-i*l;
          }
          else
            eachThreadLength[i]=l;
        }
      }
      private String GetFileName(String file)
      {
        StringTokenizer st=new StringTokenizer(file,"/");
        while(st.hasMoreTokens())
        {
          file=st.nextToken();
        }
        return file;
      }
      private void init()
      {
        
        if(!new File(localFileAddress+"tmp").mkdir())//创建一个临时文件夹
        {
          System.out.println("创建文件夹失败!");
        }
        eachThreadLength=new long[threadNum];
        try
        {
          url=new URL(urlFile);
          httpURLConnection=(HttpURLConnection)url.openConnection();
          urlFileLength=Long.parseLong(httpURLConnection.getHeaderField("Content-Length"));      
          urlFileName=url.getFile();//取得在服务器上的路径及文件名
          urlFileName=GetFileName(urlFileName);//只得文件名
          init_getEachThreadLength();
          httpURLConnection.disconnect();
          checkList=new boolean[threadNum+1];
          for(int i=1;i<=threadNum;i++)
          {
            if(i>1)
              startPos=startPos+eachThreadLength[i-2];
            endPos=startPos+eachThreadLength[i-1];
            currentFileThreadName=localFileAddress+"tmp\\"+urlFileName+".part"+i;
            //System.out.println("startPos:"+(startPos));
            //System.out.println("endPos:"+(endPos));
            //System.out.println("Size:"+(endPos-startPos));
            Thread thread=new Thread(new GetFileThread(urlFile,startPos,endPos,currentFileThreadName,i));
            thread.start();
            checkList[i]=false;//表示该线程开始
          }
          Thread policeThread=new Thread(new PoliceThread(threadNum,localFileAddress,localFileAddress+"tmp"));
          policeThread.start();
        }
        catch (Exception e)
        {
          e.printStackTrace();
        }
      }
      public void run()
      {
        init();
      }
    }
      

  2.   

    1.是否乱码要看别人提供的是什么格式的编码字段。2.Content-Disposition是一个属性名,好像是以原文件名下载。
      

  3.   

    tika新版本据说使用了某智能编码识别,icu4j?
      

  4.   

    1、编码问题,需要考虑服务器返回的编码设置,比如content-type的charset字段,如果返回的是utf8,你用gbk解码应该会有问题
    2、Content-Disposition一般是下载时,服务器用来设置文件名用,如果服务器下载时没提供这个报头,一般有个默认的文件名,好像是download,这样就比较难解析出真实文件名了,因为报头没有其他可用信息